diff --git a/pom.xml b/pom.xml index 192a372330..bb54458427 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,7 @@ true true true + true UTF-8 UTF-8 @@ -949,6 +950,12 @@ **/org/apache/activemq/artemis/utils/json/** **/org/apache/activemq/artemis/utils/Base64.java ratReport.txt + + **/*.data + **/*.bin + **/src/test/resources/keystore + **/*.log + **/*.redo diff --git a/tests/activemq5-unit-tests/README.md b/tests/activemq5-unit-tests/README.md new file mode 100644 index 0000000000..99e17b83a1 --- /dev/null +++ b/tests/activemq5-unit-tests/README.md @@ -0,0 +1,15 @@ +# ActiveMQ 5 unit tests against ActiveMQ Artemis wrapper + + +This maven module is used to run ActiveMQ5 unit tests against +ActiveMQ Artemis broker. + +The Artemis broker is 'wrapped' in BrokerService and the unit +tests are slightly modified. + +Then run the tests simply do + +```mvn -DskipActiveMQTests=false clean test``` + +It will kickoff the whole test suite. + diff --git a/tests/activemq5-unit-tests/pom.xml b/tests/activemq5-unit-tests/pom.xml new file mode 100644 index 0000000000..d6d87e8e92 --- /dev/null +++ b/tests/activemq5-unit-tests/pom.xml @@ -0,0 +1,387 @@ + + + 4.0.0 + + + org.apache.activemq.tests + artemis-tests-pom + 1.0.0-SNAPSHOT + + + activemq5-unit-tests + jar + ActiveMQ5.x unit tests + + + ${project.basedir}/../.. + 5.11.1 + 3.4.1 + 1.0.6 + 2.5.1 + 3.2.11.RELEASE + 10.11.1.1 + 2.4 + 3.3 + 0.30 + 3.18 + 1.3 + 1.7.10 + 1.9.2 + 2.0.0-M6 + 3.1.4 + + + + + + + org.apache.activemq + activemq-client + ${activemq5.project.version} + + + + org.apache.activemq + activemq-jaas + ${activemq5.project.version} + + + + org.apache.activemq + activemq-broker + ${activemq5.project.version} + test-jar + + + + org.apache.activemq + activemq-jdbc-store + ${activemq5.project.version} + + + + org.apache.activemq + activemq-kahadb-store + ${activemq5.project.version} + + + + org.apache.activemq + activemq-leveldb-store + ${activemq5.project.version} + + + + org.apache.activemq + activemq-pool + ${activemq5.project.version} + + + + org.apache.activemq + activemq-spring + ${activemq5.project.version} + + + + org.apache.activemq + activemq-partition + ${activemq5.project.version} + + + + org.apache.activemq + activemq-stomp + ${activemq5.project.version} + + + + org.apache.activemq + activemq-console + ${activemq5.project.version} + + + + org.apache.activemq + activeio-core + ${activeio-core-version} + + + + junit + junit + 4.11 + compile + + + + org.osgi + org.osgi.core + 4.3.1 + + + + javax.jmdns + jmdns + ${jmdns-version} + + + + org.apache.ftpserver + ftpserver-core + ${ftpserver-version} + test + + + + org.jmock + jmock-junit4 + ${jmock-version} + test + + + + org.jmock + jmock-legacy + ${jmock-version} + test + + + + org.springframework + spring-jms + ${spring-version} + test + + + + org.apache.derby + derby + ${org-apache-derby-version} + test + + + + commons-io + commons-io + ${commons-io-version} + test + + + + commons-net + commons-net + ${commons-net-version} + + + + org.apache.qpid + qpid-amqp-1-0-client-jms + ${qpid-jms-version} + test + + + + org.apache.xbean + xbean-spring + ${xbean-version} + test + + + + org.hamcrest + hamcrest-all + ${hamcrest-version} + test + + + + org.slf4j + slf4j-log4j12 + ${slf4j-version} + test + + + + log4j + log4j + test + + + + org.springframework + spring-test + ${spring-version} + test + + + + org.jasypt + jasypt + ${jasypt-version} + + + + org.jasypt + jasypt-spring31 + ${jasypt-version} + true + + + + org.apache.directory.server + apacheds-core-integ + ${directory-version} + test + + + bouncycastle + bcprov-jdk15 + + + + + + org.bouncycastle + bcprov-jdk15 + 1.46 + test + + + + org.apache.directory.server + apacheds-server-integ + ${directory-version} + test + + + + org.fusesource.joram-jms-tests + joram-jms-tests + 1.0 + test + + + + org.easymock + easymock + 3.2 + test + + + + org.fusesource.mqtt-client + mqtt-client + 1.10 + test + + + + + org.apache.activemq + artemis-commons + ${project.version} + + + + org.apache.activemq + artemis-server + ${project.version} + + + + org.apache.activemq + artemis-openwire-protocol + ${project.version} + + + + + + + + org.apache.rat + apache-rat-plugin + 0.11 + + ${activemq.basedir}/ratReport.txt + ${skipLicenseCheck} + + **/*.data + **/*.bin + **/*.log + **/*.redo + **/src/test/resources/keystore + **/META-INF/services/* + **/*/*.txt + **/*.md + + + + + compile + + check + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.12 + + true + + + + compile + + check + + + + + + + org.apache.felix + maven-bundle-plugin + 2.5.3 + true + true + + + org.apache.activemq.util.osgi.Activator + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipActiveMQ5Tests} + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/artemiswrapper/ArtemisBrokerHelper.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/artemiswrapper/ArtemisBrokerHelper.java new file mode 100644 index 0000000000..8d5cdabc38 --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/artemiswrapper/ArtemisBrokerHelper.java @@ -0,0 +1,76 @@ +/** + * 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.artemiswrapper; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; + +import org.apache.activemq.command.ActiveMQDestination; + +public class ArtemisBrokerHelper { + + private static volatile Object service = null; + private static Class serviceClass; + + static { + try { + serviceClass = Class.forName("org.apache.activemq.broker.BrokerService"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + } + // start a tcp transport artemis broker, the broker need to + // be invm with client. + public static void startArtemisBroker(URI location) throws IOException { + if (service != null) { + return; + } + try { + service = serviceClass.newInstance(); + Method startMethod = serviceClass.getMethod("start"); + startMethod.invoke(service, (Object[]) null); + } catch (InstantiationException e) { + throw new IOException("Inst exception", e); + } catch (IllegalAccessException e) { + throw new IOException("IllegalAccess exception ", e); + } catch (NoSuchMethodException e) { + throw new IOException("Nosuchmethod", e); + } catch (SecurityException e) { + throw new IOException("Security exception", e); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException exception", e); + } catch (InvocationTargetException e) { + throw new IOException("InvocationTargetException exception", e); + } + } + + public static void makeSureDestinationExists(ActiveMQDestination activemqDestination) throws Exception { + Method startMethod = serviceClass.getMethod("makeSureDestinationExists", ActiveMQDestination.class); + startMethod.invoke(service, activemqDestination); + } + + //some tests run broker in setUp(). This need be called + //to prevent auto broker creation. + public static void setBroker(Object startedBroker) { + service = startedBroker; + } + +} + diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/BrokerService.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/BrokerService.java new file mode 100644 index 0000000000..cf9c93909c --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/BrokerService.java @@ -0,0 +1,811 @@ +/** + * 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.broker; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.security.Provider; +import java.security.Security; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionMetaData; +import org.apache.activemq.ConfigurationException; +import org.apache.activemq.Service; +import org.apache.activemq.advisory.AdvisoryBroker; +import org.apache.activemq.broker.artemiswrapper.ArtemisBrokerWrapper; +import org.apache.activemq.broker.cluster.ConnectionSplitBroker; +import org.apache.activemq.broker.jmx.AnnotatedMBean; +import org.apache.activemq.broker.jmx.BrokerMBeanSupport; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.broker.jmx.ConnectorView; +import org.apache.activemq.broker.jmx.ConnectorViewMBean; +import org.apache.activemq.broker.jmx.HealthView; +import org.apache.activemq.broker.jmx.HealthViewMBean; +import org.apache.activemq.broker.jmx.JmsConnectorView; +import org.apache.activemq.broker.jmx.JobSchedulerView; +import org.apache.activemq.broker.jmx.JobSchedulerViewMBean; +import org.apache.activemq.broker.jmx.Log4JConfigView; +import org.apache.activemq.broker.jmx.ManagedRegionBroker; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.broker.jmx.NetworkConnectorView; +import org.apache.activemq.broker.jmx.NetworkConnectorViewMBean; +import org.apache.activemq.broker.jmx.ProxyConnectorView; +import org.apache.activemq.broker.region.CompositeDestinationInterceptor; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.DestinationFactory; +import org.apache.activemq.broker.region.DestinationFactoryImpl; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.virtual.MirroredQueue; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.broker.scheduler.JobSchedulerStore; +import org.apache.activemq.broker.scheduler.SchedulerBroker; +import org.apache.activemq.broker.scheduler.memory.InMemoryJobSchedulerStore; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.filter.DestinationFilter; +import org.apache.activemq.network.ConnectionFilter; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.network.jms.JmsConnector; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.proxy.ProxyConnector; +import org.apache.activemq.security.MessageAuthorizationPolicy; +import org.apache.activemq.selector.SelectorParser; +import org.apache.activemq.store.JournaledStore; +import org.apache.activemq.store.PListStore; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.PersistenceAdapterFactory; +import org.apache.activemq.store.memory.MemoryPersistenceAdapter; +import org.apache.activemq.thread.Scheduler; +import org.apache.activemq.thread.TaskRunnerFactory; +import org.apache.activemq.transport.TransportFactorySupport; +import org.apache.activemq.transport.TransportServer; +import org.apache.activemq.transport.vm.VMTransportFactory; +import org.apache.activemq.usage.SystemUsage; +import org.apache.activemq.util.BrokerSupport; +import org.apache.activemq.util.DefaultIOExceptionHandler; +import org.apache.activemq.util.IOExceptionHandler; +import org.apache.activemq.util.IOExceptionSupport; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.InetAddressUtil; +import org.apache.activemq.util.ServiceStopper; +import org.apache.activemq.util.ThreadPoolUtils; +import org.apache.activemq.util.TimeUtils; +import org.apache.activemq.util.URISupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +/** + * Manages the life-cycle of an ActiveMQ Broker. A BrokerService consists of a + * number of transport connectors, network connectors and a bunch of properties + * which can be used to configure the broker as its lazily created. + * + * @org.apache.xbean.XBean + */ +public class BrokerService implements Service +{ + public static final String DEFAULT_PORT = "61616"; + public static final String DEFAULT_BROKER_NAME = "localhost"; + public static final String BROKER_VERSION; + public static final int DEFAULT_MAX_FILE_LENGTH = 1024 * 1024 * 32; + public static final long DEFAULT_START_TIMEOUT = 600000L; + + public String SERVER_SIDE_KEYSTORE; + public String KEYSTORE_PASSWORD; + public String SERVER_SIDE_TRUSTSTORE; + public String TRUSTSTORE_PASSWORD; + public String storeType; + + private static final Logger LOG = LoggerFactory.getLogger(BrokerService.class); + + @SuppressWarnings("unused") + private static final long serialVersionUID = 7353129142305630237L; + + private String brokerName = DEFAULT_BROKER_NAME; + private Broker broker; + private BrokerId brokerId; + private Throwable startException = null; + private boolean startAsync = false; + public Set extraConnectors = new HashSet(); + private File dataDirectoryFile; + + static + { + InputStream in; + String version = null; + if ((in = BrokerService.class.getResourceAsStream("/org/apache/activemq/version.txt")) != null) + { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + try + { + version = reader.readLine(); + } + catch (Exception e) + { + } + } + BROKER_VERSION = version; + } + + @Override + public String toString() + { + return "BrokerService[" + getBrokerName() + "]"; + } + + private String getBrokerVersion() + { + String version = ActiveMQConnectionMetaData.PROVIDER_VERSION; + if (version == null) + { + version = BROKER_VERSION; + } + + return version; + } + + + @Override + public void start() throws Exception + { + startBroker(startAsync); + } + + private void startBroker(boolean async) throws Exception + { + if (async) + { + new Thread("Broker Starting Thread") + { + @Override + public void run() + { + try + { + doStartBroker(); + } + catch (Throwable t) + { + startException = t; + } + } + }.start(); + } + else + { + doStartBroker(); + } + } + + private void doStartBroker() throws Exception + { + if (startException != null) + { + return; + } + + broker = getBroker(); + brokerId = broker.getBrokerId(); + + LOG.info("Apache ActiveMQ Artemis Wrapper {} ({}, {}) is starting", new Object[]{getBrokerVersion(), getBrokerName(), brokerId}); + + try + { + broker.start(); + } + catch (Exception e) + { + throw e; + } + catch (Throwable t) + { + throw new Exception(t); + } + + LOG.info("Apache ActiveMQ Artemis Wrapper {} ({}, {}) started", new Object[]{getBrokerVersion(), getBrokerName(), brokerId}); + LOG.info("For help or more information please see: http://activemq.apache.org"); + + } + + + /** + * @throws Exception + * @org.apache .xbean.DestroyMethod + */ + @Override + public void stop() throws Exception + { + + LOG.info("Apache ActiveMQ Artemis{} ({}, {}) is shutting down", new Object[]{getBrokerVersion(), getBrokerName(), brokerId}); + + if (broker != null) + { + broker.stop(); + broker = null; + } + LOG.info("Apache ActiveMQ Artemis {} ({}, {}) is shutdown", new Object[]{getBrokerVersion(), getBrokerName(), brokerId}); + } + + // Properties + // ------------------------------------------------------------------------- + + /** + * Returns the message broker + */ + public Broker getBroker() throws Exception + { + if (broker == null) + { + broker = createBroker(); + } + return broker; + } + + public String getBrokerName() + { + return brokerName; + } + + /** + * Sets the name of this broker; which must be unique in the network + * + * @param brokerName + */ + public void setBrokerName(String brokerName) + { + if (brokerName == null) + { + throw new NullPointerException("The broker name cannot be null"); + } + String str = brokerName.replaceAll("[^a-zA-Z0-9\\.\\_\\-\\:]", "_"); + if (!str.equals(brokerName)) + { + LOG.error("Broker Name: {} contained illegal characters - replaced with {}", brokerName, str); + } + this.brokerName = str.trim(); + } + + /** + * Factory method to create a new broker + * + * @throws Exception + * @throws + * @throws + */ + protected Broker createBroker() throws Exception + { + broker = createBrokerWrapper(); + return broker; + } + + private Broker createBrokerWrapper() + { + return new ArtemisBrokerWrapper(this); + } + + public void makeSureDestinationExists(ActiveMQDestination activemqDestination) throws Exception + { + System.out.println(">>>> making sure dest exits: " + activemqDestination); + ArtemisBrokerWrapper hqBroker = (ArtemisBrokerWrapper) this.broker; + //it can be null + if (activemqDestination == null) + { + return; + } + if (activemqDestination.isQueue()) + { + String qname = activemqDestination.getPhysicalName(); + System.out.println("physical name: " + qname); + hqBroker.makeSureQueueExists(qname); + } + } + + public boolean enableSsl() + { + return this.SERVER_SIDE_KEYSTORE != null; + } + + //below are methods called directly by tests + //we don't actually implement any of these for now, + //just to make test compile pass. + + //we may get class cast exception as in TestSupport it + //casts the broker to RegionBroker, which we didn't + //implement (wrap) yet. Consider solving it later. + public Broker getRegionBroker() + { + return broker; + } + + public void setPersistenceAdapter(PersistenceAdapter persistenceAdapter) throws IOException + { + } + + public File getDataDirectoryFile() + { + if (dataDirectoryFile == null) + { + dataDirectoryFile = new File(IOHelper.getDefaultDataDirectory()); + } + return dataDirectoryFile; + } + + public File getBrokerDataDirectory() + { + String brokerDir = getBrokerName(); + return new File(getDataDirectoryFile(), brokerDir); + } + + public PersistenceAdapter getPersistenceAdapter() throws IOException + { + return null; + } + + public void waitUntilStopped() + { + } + + public boolean waitUntilStarted() + { + return true; + } + + public void setDestinationPolicy(PolicyMap policyMap) + { + } + + public void setDeleteAllMessagesOnStartup(boolean deletePersistentMessagesOnStartup) + { + } + + public void setUseJmx(boolean useJmx) + { + } + + public ManagementContext getManagementContext() + { + return null; + } + + public BrokerView getAdminView() throws Exception + { + return null; + } + + public List getTransportConnectors() + { + return new ArrayList<>(); + } + + public TransportConnector addConnector(String bindAddress) throws Exception + { + return null; + } + + public void setIoExceptionHandler(IOExceptionHandler ioExceptionHandler) + { + } + + public void setPersistent(boolean persistent) + { + } + + public boolean isSlave() + { + return false; + } + + public Destination getDestination(ActiveMQDestination destination) throws Exception + { + return null; + } + + public void setAllowTempAutoCreationOnSend(boolean allowTempAutoCreationOnSend) + { + } + + public void setDedicatedTaskRunner(boolean dedicatedTaskRunner) + { + } + + public void setAdvisorySupport(boolean advisorySupport) + { + } + + public void setUseShutdownHook(boolean useShutdownHook) + { + } + + public void deleteAllMessages() throws IOException + { + } + + public Service[] getServices() + { + return null; + } + + public void setPopulateUserNameInMBeans(boolean value) + { + } + + public void setDestinations(ActiveMQDestination[] destinations) + { + } + + public URI getVmConnectorURI() + { + return null; + } + + public SystemUsage getSystemUsage() + { + return null; + } + + public synchronized PListStore getTempDataStore() + { + return null; + } + + public void setJmsBridgeConnectors(JmsConnector[] jmsConnectors) + { + } + + public void setDestinationInterceptors(DestinationInterceptor[] destinationInterceptors) + { + } + + public SslContext getSslContext() + { + return null; + } + + public void setDataDirectory(String dataDirectory) + { + } + + public void setPlugins(BrokerPlugin[] plugins) + { + } + + public void setKeepDurableSubsActive(boolean keepDurableSubsActive) + { + } + + public NetworkConnector addNetworkConnector(String discoveryAddress) throws Exception + { + return null; + } + + public TransportConnector getConnectorByName(String connectorName) + { + return null; + } + + public TransportConnector addConnector(TransportConnector connector) throws Exception + { + return connector; + } + + public void setEnableStatistics(boolean enableStatistics) + { + } + + public void setSystemUsage(SystemUsage memoryManager) + { + } + + public void setManagementContext(ManagementContext managementContext) + { + } + + public void setSchedulerDirectoryFile(File schedulerDirectory) + { + } + + public List getNetworkConnectors() + { + return new ArrayList<>(); + } + + public void setSchedulerSupport(boolean schedulerSupport) + { + } + + public void setPopulateJMSXUserID(boolean populateJMSXUserID) + { + } + + public boolean isUseJmx() + { + return false; + } + + public boolean isPersistent() + { + return false; + } + + public TransportConnector getTransportConnectorByScheme(String scheme) + { + return null; + } + + public TaskRunnerFactory getTaskRunnerFactory() + { + return null; + } + + public boolean isStarted() + { + if (broker == null) return false; + return !broker.isStopped(); + } + + public ProxyConnector addProxyConnector(ProxyConnector connector) throws Exception + { + return connector; + } + + public void setDataDirectoryFile(File dataDirectoryFile) + { + this.dataDirectoryFile = dataDirectoryFile; + } + + public PolicyMap getDestinationPolicy() + { + return null; + } + + public void setTransportConnectorURIs(String[] transportConnectorURIs) + { + } + + public boolean isPopulateJMSXUserID() + { + return false; + } + + public NetworkConnector getNetworkConnectorByName(String connectorName) + { + return null; + } + + public boolean removeNetworkConnector(NetworkConnector connector) + { + return true; + } + + public void setTransportConnectors(List transportConnectors) throws Exception + { + } + + public NetworkConnector addNetworkConnector(NetworkConnector connector) throws Exception + { + return connector; + } + + public void setTempDataStore(PListStore tempDataStore) + { + } + + public void setJobSchedulerStore(JobSchedulerStore jobSchedulerStore) + { + } + + public ObjectName getBrokerObjectName() throws MalformedObjectNameException + { + return null; + } + + public TransportConnector addConnector(URI bindAddress) throws Exception + { + return null; + } + + public void setCacheTempDestinations(boolean cacheTempDestinations) + { + } + + public void setOfflineDurableSubscriberTimeout(long offlineDurableSubscriberTimeout) + { + } + + public void setOfflineDurableSubscriberTaskSchedule(long offlineDurableSubscriberTaskSchedule) + { + } + + public boolean isStopped() + { + return broker.isStopped(); + } + + public void setBrokerId(String brokerId) + { + } + + public BrokerPlugin[] getPlugins() + { + return null; + } + + public void stopAllConnectors(ServiceStopper stopper) + { + } + + public void setMessageAuthorizationPolicy(MessageAuthorizationPolicy messageAuthorizationPolicy) + { + } + + public void setNetworkConnectorStartAsync(boolean networkConnectorStartAsync) + { + } + + public boolean isRestartAllowed() + { + return true; + } + + public void setTaskRunnerFactory(TaskRunnerFactory taskRunnerFactory) + { + } + + public void start(boolean force) throws Exception + { + this.start(); + } + + public void setMonitorConnectionSplits(boolean monitorConnectionSplits) + { + } + + public void setUseMirroredQueues(boolean useMirroredQueues) + { + } + + public File getTmpDataDirectory() + { + return null; + } + + public boolean isUseShutdownHook() + { + return true; + } + + public boolean isDeleteAllMessagesOnStartup() + { + return false; + } + + public void setUseVirtualTopics(boolean useVirtualTopics) + { + } + + public boolean isUseLoggingForShutdownErrors() + { + return true; + } + + public TransportConnector addConnector(TransportServer transport) throws Exception + { + return null; + } + + public synchronized JobSchedulerStore getJobSchedulerStore() + { + return null; + } + + public boolean removeConnector(TransportConnector connector) throws Exception + { + return true; + } + + public ConnectionContext getAdminConnectionContext() throws Exception { + return null; + } + + public void setUseAuthenticatedPrincipalForJMSXUserID(boolean useAuthenticatedPrincipalForJMSXUserID) + { + } + + public void setSchedulePeriodForDestinationPurge(int schedulePeriodForDestinationPurge) + { + } + + public void setMbeanInvocationTimeout(long mbeanInvocationTimeout) + { + } + + public void setNetworkConnectors(List networkConnectors) throws Exception + { + } + + public void removeDestination(ActiveMQDestination destination) throws Exception + { + } + + public void setMaxPurgedDestinationsPerSweep(int maxPurgedDestinationsPerSweep) + { + } + + public void setBrokerObjectName(ObjectName brokerObjectName) + { + } + + public Map getTransportConnectorURIsAsMap() + { + return null; + } + + public void setSslContext(SslContext sslContext) + { + } + + public void setPersistenceFactory(PersistenceAdapterFactory persistenceFactory) + { + } + + protected TransportConnector createTransportConnector(URI brokerURI) throws Exception + { + return null; + } + +} + + + diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/SslBrokerService.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/SslBrokerService.java new file mode 100644 index 0000000000..9699cf3f85 --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/SslBrokerService.java @@ -0,0 +1,61 @@ +/** + * 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.broker; + +import org.apache.activemq.transport.TransportFactorySupport; +import org.apache.activemq.transport.TransportServer; +import org.apache.activemq.transport.tcp.SslTransportFactory; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.TrustManager; +import java.io.IOException; +import java.net.URI; +import java.security.KeyManagementException; +import java.security.SecureRandom; + +/** + * A BrokerService that allows access to the key and trust managers used by SSL + * connections. There is no reason to use this class unless SSL is being used + * AND the key and trust managers need to be specified from within code. In + * fact, if the URI passed to this class does not have an "ssl" scheme, this + * class will pass all work on to its superclass. + * + * @author sepandm@gmail.com (Sepand) + */ +public class SslBrokerService extends BrokerService +{ + + public TransportConnector addSslConnector(String bindAddress, KeyManager[] km, TrustManager[] tm, SecureRandom random) throws Exception { + return null; + } + + public TransportConnector addSslConnector(URI bindAddress, KeyManager[] km, TrustManager[] tm, SecureRandom random) throws Exception { + return null; + } + + protected TransportServer createSslTransportServer(URI brokerURI, KeyManager[] km, TrustManager[] tm, SecureRandom random) throws IOException, KeyManagementException { + return null; + } + + //one way + public void setupSsl(String keystoreType, String password, String serverKeystore) { + this.SERVER_SIDE_KEYSTORE = serverKeystore; + this.KEYSTORE_PASSWORD = password; + this.storeType = keystoreType; + } +} diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/ArtemisBrokerBase.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/ArtemisBrokerBase.java new file mode 100644 index 0000000000..227ad1b10e --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/ArtemisBrokerBase.java @@ -0,0 +1,674 @@ +/** + * 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.broker.artemiswrapper; + + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ThreadPoolExecutor; + +import org.apache.activemq.artemis.api.core.TransportConfiguration; +import org.apache.activemq.artemis.core.asyncio.impl.AsynchronousFileImpl; +import org.apache.activemq.artemis.core.config.Configuration; +import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; +import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory; +import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory; +import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.core.server.ActiveMQServers; +import org.apache.activemq.artemis.core.server.JournalType; +import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy; +import org.apache.activemq.artemis.core.settings.impl.AddressSettings; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.Connection; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.ConsumerBrokerExchange; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.MessageReference; +import org.apache.activemq.broker.region.Subscription; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerControl; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.DestinationInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatch; +import org.apache.activemq.command.MessageDispatchNotification; +import org.apache.activemq.command.MessagePull; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.RemoveSubscriptionInfo; +import org.apache.activemq.command.Response; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.store.PListStore; +import org.apache.activemq.thread.Scheduler; +import org.apache.activemq.usage.Usage; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class ArtemisBrokerBase implements Broker { + + private static final Logger LOG = LoggerFactory + .getLogger(ArtemisBrokerBase.class); + public static final String INVM_ACCEPTOR_FACTORY = InVMAcceptorFactory.class + .getCanonicalName(); + + public static final String NETTY_ACCEPTOR_FACTORY = NettyAcceptorFactory.class + .getCanonicalName(); + + public static final String NETTY_CONNECTOR_FACTORY = NettyConnectorFactory.class + .getCanonicalName(); + + protected static final String CLUSTER_PASSWORD = "UnitTestsClusterPassword"; + + protected volatile boolean stopped; + protected BrokerId brokerId = new BrokerId("Artemis Broker"); + protected BrokerService bservice; + protected TemporaryFolder temporaryFolder = new TemporaryFolder(); + protected String testDir; + protected boolean realStore = false; + + protected ActiveMQServer server; + + protected boolean enableSecurity = false; + + public ArtemisBrokerBase() { + try { + this.temporaryFolder.create(); + } catch (IOException e) { + } + } + @Override + public Destination addDestination(ConnectionContext context, + ActiveMQDestination destination, boolean createIfTemporary) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void removeDestination(ConnectionContext context, + ActiveMQDestination destination, long timeout) throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public Map getDestinationMap() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void removeConsumer(ConnectionContext context, ConsumerInfo info) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void removeSubscription(ConnectionContext context, + RemoveSubscriptionInfo info) throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void send(ProducerBrokerExchange producerExchange, Message message) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void acknowledge(ConsumerBrokerExchange consumerExchange, + MessageAck ack) throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public Response messagePull(ConnectionContext context, MessagePull pull) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void processDispatchNotification( + MessageDispatchNotification messageDispatchNotification) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void gc() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public Set getDestinations(ActiveMQDestination destination) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void processConsumerControl(ConsumerBrokerExchange consumerExchange, + ConsumerControl control) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void reapplyInterceptor() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public Broker getAdaptor(Class type) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public BrokerId getBrokerId() { + return brokerId; + } + + @Override + public String getBrokerName() { + return "Artemis Broker"; + } + + @Override + public void addBroker(Connection connection, BrokerInfo info) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void removeBroker(Connection connection, BrokerInfo info) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void addConnection(ConnectionContext context, ConnectionInfo info) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void removeConnection(ConnectionContext context, + ConnectionInfo info, Throwable error) throws Exception { + throw new RuntimeException("Don't call me!"); + + } + + @Override + public void addSession(ConnectionContext context, SessionInfo info) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void removeSession(ConnectionContext context, SessionInfo info) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void addProducer(ConnectionContext context, ProducerInfo info) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void removeProducer(ConnectionContext context, ProducerInfo info) + throws Exception { + throw new RuntimeException("Don't call me!"); + + } + + @Override + public Connection[] getClients() throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public ActiveMQDestination[] getDestinations() throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public Map getDestinationMap( + ActiveMQDestination destination) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public TransactionId[] getPreparedTransactions(ConnectionContext context) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void beginTransaction(ConnectionContext context, TransactionId xid) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public int prepareTransaction(ConnectionContext context, TransactionId xid) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void rollbackTransaction(ConnectionContext context, TransactionId xid) + throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void commitTransaction(ConnectionContext context, TransactionId xid, + boolean onePhase) throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void forgetTransaction(ConnectionContext context, + TransactionId transactionId) throws Exception { + throw new RuntimeException("Don't call me!"); + } + + @Override + public BrokerInfo[] getPeerBrokerInfos() { + return null; + } + + @Override + public void preProcessDispatch(MessageDispatch messageDispatch) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void postProcessDispatch(MessageDispatch messageDispatch) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public boolean isStopped() { + return stopped; + } + + @Override + public Set getDurableDestinations() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void addDestinationInfo(ConnectionContext context, + DestinationInfo info) throws Exception { + throw new RuntimeException("Don't call me!"); + + } + + @Override + public void removeDestinationInfo(ConnectionContext context, + DestinationInfo info) throws Exception { + throw new RuntimeException("Don't call me!"); + + } + + @Override + public boolean isFaultTolerantConfiguration() { + return false; + } + + @Override + public ConnectionContext getAdminConnectionContext() { + return null; + } + + @Override + public void setAdminConnectionContext( + ConnectionContext adminConnectionContext) { + // + } + + @Override + public PListStore getTempDataStore() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public URI getVmConnectorURI() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void brokerServiceStarted() { + stopped = false; + } + + @Override + public BrokerService getBrokerService() { + return this.bservice; + } + + @Override + public Broker getRoot() { + return this; + } + + @Override + public boolean isExpired(MessageReference messageReference) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void messageExpired(ConnectionContext context, + MessageReference messageReference, Subscription subscription) { + throw new RuntimeException("Don't call me!"); + + } + + @Override + public boolean sendToDeadLetterQueue(ConnectionContext context, + MessageReference messageReference, Subscription subscription, + Throwable poisonCause) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public long getBrokerSequenceId() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void messageConsumed(ConnectionContext context, + MessageReference messageReference) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void messageDelivered(ConnectionContext context, + MessageReference messageReference) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void messageDiscarded(ConnectionContext context, Subscription sub, + MessageReference messageReference) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void slowConsumer(ConnectionContext context, + Destination destination, Subscription subs) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void fastProducer(ConnectionContext context, + ProducerInfo producerInfo, ActiveMQDestination destination) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void isFull(ConnectionContext context, Destination destination, + Usage usage) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void nowMasterBroker() { + } + + @Override + public Scheduler getScheduler() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public ThreadPoolExecutor getExecutor() { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void networkBridgeStarted(BrokerInfo brokerInfo, + boolean createdByDuplex, String remoteIp) { + throw new RuntimeException("Don't call me!"); + } + + @Override + public void networkBridgeStopped(BrokerInfo brokerInfo) { + throw new RuntimeException("Don't call me!"); + } + + protected final ActiveMQServer createServer(final boolean realFiles, + final boolean netty) throws Exception { + return createServer(realFiles, createDefaultConfig(netty), -1, -1, + new HashMap()); + } + + protected final ActiveMQServer createServer(final boolean realFiles, + final Configuration configuration, final int pageSize, + final int maxAddressSize, + final Map settings) { + return createServer(realFiles, configuration, pageSize, maxAddressSize, + AddressFullMessagePolicy.PAGE, settings); + } + + protected final ActiveMQServer createServer(final boolean realFiles, + final Configuration configuration, final int pageSize, + final int maxAddressSize, + final AddressFullMessagePolicy fullPolicy, + final Map settings) { + ActiveMQServer server = ActiveMQServers.newActiveMQServer(configuration, + realFiles); + if (settings != null) { + for (Map.Entry setting : settings + .entrySet()) { + server.getAddressSettingsRepository().addMatch( + setting.getKey(), setting.getValue()); + } + } + + AddressSettings defaultSetting = new AddressSettings(); + defaultSetting.setPageSizeBytes(pageSize); + defaultSetting.setMaxSizeBytes(maxAddressSize); + defaultSetting.setAddressFullMessagePolicy(fullPolicy); + + server.getAddressSettingsRepository().addMatch("#", defaultSetting); + + return server; + } + + protected Configuration createDefaultConfig(final boolean netty) + throws Exception { + if (netty) { + return createDefaultConfig(new HashMap(), + INVM_ACCEPTOR_FACTORY, NETTY_ACCEPTOR_FACTORY); + } else { + return createDefaultConfig(new HashMap(), + INVM_ACCEPTOR_FACTORY); + } + } + + protected Configuration createDefaultConfig( + final Map params, final String... acceptors) + throws Exception { + ConfigurationImpl configuration = createBasicConfig(-1) + .setJMXManagementEnabled(false) + .clearAcceptorConfigurations(); + + for (String acceptor : acceptors) { + TransportConfiguration transportConfig = new TransportConfiguration( + acceptor, params); + configuration.addAcceptorConfiguration(transportConfig); + } + + return configuration; + } + + protected final 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); + + return configuration; + } + + protected String getLargeMessagesDir(final int index, final boolean backup) { + return getLargeMessagesDir(testDir, index, backup); + } + + protected static String getLargeMessagesDir(final String testDir, + final int index, final boolean backup) { + return getLargeMessagesDir(testDir) + + directoryNameSuffix(index, backup); + } + + protected String getPageDir(final int index, final boolean backup) { + return getPageDir(testDir, index, backup); + } + + protected static String getPageDir(final String testDir, final int index, + final boolean backup) { + return getPageDir(testDir) + directoryNameSuffix(index, backup); + } + + protected String getBindingsDir(final int index, final boolean backup) { + return getBindingsDir(testDir, index, backup); + } + + protected static String getBindingsDir(final String testDir, + final int index, final boolean backup) { + return getBindingsDir(testDir) + directoryNameSuffix(index, backup); + } + + protected String getJournalDir(final int index, final boolean backup) { + return getJournalDir(testDir, index, backup); + } + + protected static String getJournalDir(final String testDir, + final int index, final boolean backup) { + return getJournalDir(testDir) + directoryNameSuffix(index, backup); + } + + private static String directoryNameSuffix(int index, boolean backup) { + if (index == -1) + return ""; + return index + "-" + (backup ? "B" : "L"); + } + + protected static JournalType getDefaultJournalType() { + if (AsynchronousFileImpl.isLoaded()) { + return JournalType.ASYNCIO; + } else { + return JournalType.NIO; + } + } + + protected final void clearDataRecreateServerDirs() { + clearDataRecreateServerDirs(testDir); + } + + protected void clearDataRecreateServerDirs(final String testDir1) { + // Need to delete the root + + File file = new File(testDir1); + deleteDirectory(file); + file.mkdirs(); + + recreateDirectory(getJournalDir(testDir1)); + recreateDirectory(getBindingsDir(testDir1)); + recreateDirectory(getPageDir(testDir1)); + recreateDirectory(getLargeMessagesDir(testDir1)); + recreateDirectory(getClientLargeMessagesDir(testDir1)); + recreateDirectory(getTemporaryDir(testDir1)); + } + + protected String getTemporaryDir(final String testDir1) { + return testDir1 + "/temp"; + } + + protected String getClientLargeMessagesDir(final String testDir1) { + return testDir1 + "/client-large-msg"; + } + + protected static String getLargeMessagesDir(final String testDir1) { + return testDir1 + "/large-msg"; + } + + protected static String getPageDir(final String testDir1) { + return testDir1 + "/page"; + } + + protected static String getBindingsDir(final String testDir1) { + return testDir1 + "/bindings"; + } + + protected static String getJournalDir(final String testDir1) { + return testDir1 + "/journal"; + } + + 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) { + if (directory.isDirectory()) { + String[] files = directory.list(); + int num = 5; + int attempts = 0; + while (files == null && (attempts < num)) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + files = directory.list(); + attempts++; + } + + for (String file : files) { + File f = new File(directory, file); + if (!deleteDirectory(f)) { + LOG.warn("Failed to clean up file: " + f.getAbsolutePath()); + } + } + } + + return directory.delete(); + } + +} diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/ArtemisBrokerWrapper.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/ArtemisBrokerWrapper.java new file mode 100644 index 0000000000..86580e1c75 --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/ArtemisBrokerWrapper.java @@ -0,0 +1,209 @@ +/** + * 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.broker.artemiswrapper; + +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException; +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.api.core.TransportConfiguration; +import org.apache.activemq.artemis.core.config.Configuration; +import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration; +import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants; +import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.settings.impl.AddressSettings; +import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManagerImpl; +import org.apache.activemq.artemiswrapper.ArtemisBrokerHelper; +import org.apache.activemq.broker.BrokerService; + +public class ArtemisBrokerWrapper extends ArtemisBrokerBase +{ + + protected Map testQueues = new HashMap(); + + public ArtemisBrokerWrapper(BrokerService brokerService) + { + this.bservice = brokerService; + } + + @Override + public void start() throws Exception + { + testDir = temporaryFolder.getRoot().getAbsolutePath(); + clearDataRecreateServerDirs(); + server = createServer(realStore, false); + HashMap params = new HashMap(); + params.put(TransportConstants.PORT_PROP_NAME, "61616"); + params.put(TransportConstants.PROTOCOLS_PROP_NAME, "OPENWIRE"); + TransportConfiguration transportConfiguration = new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params); + + Configuration serverConfig = server.getConfiguration(); + + Set acceptors0 = serverConfig.getAcceptorConfigurations(); + Iterator iter0 = acceptors0.iterator(); + + while (iter0.hasNext()) + { + System.out.println("===>: " + iter0.next()); + } + + Map addressSettings = serverConfig.getAddressesSettings(); + String match = "jms.queue.#"; + AddressSettings dlaSettings = new AddressSettings(); + SimpleString dla = new SimpleString("jms.queue.ActiveMQ.DLQ"); + dlaSettings.setDeadLetterAddress(dla); + addressSettings.put(match, dlaSettings); + + serverConfig.getAcceptorConfigurations().add(transportConfiguration); + if (this.bservice.enableSsl()) + { + params = new HashMap(); + params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true); + params.put(TransportConstants.PORT_PROP_NAME, 61611); + params.put(TransportConstants.PROTOCOLS_PROP_NAME, "OPENWIRE"); + params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, bservice.SERVER_SIDE_KEYSTORE); + params.put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, bservice.KEYSTORE_PASSWORD); + params.put(TransportConstants.KEYSTORE_PROVIDER_PROP_NAME, bservice.storeType); + if (bservice.SERVER_SIDE_TRUSTSTORE != null) + { + params.put(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, true); + params.put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, bservice.SERVER_SIDE_TRUSTSTORE); + params.put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, bservice.TRUSTSTORE_PASSWORD); + params.put(TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME, bservice.storeType); + } + TransportConfiguration sslTransportConfig = new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params); + serverConfig.getAcceptorConfigurations().add(sslTransportConfig); + } + + for (Integer port : bservice.extraConnectors) + { + if (port.intValue() != 61616) + { + //extra port + params = new HashMap(); + params.put(TransportConstants.PORT_PROP_NAME, port.intValue()); + params.put(TransportConstants.PROTOCOLS_PROP_NAME, "OPENWIRE"); + TransportConfiguration extraTransportConfiguration = new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params); + serverConfig.getAcceptorConfigurations().add(extraTransportConfiguration); + } + } + + serverConfig.setSecurityEnabled(enableSecurity); + + //extraServerConfig(serverConfig); + + if (enableSecurity) + { + ActiveMQSecurityManagerImpl sm = (ActiveMQSecurityManagerImpl) server.getSecurityManager(); + SecurityConfiguration securityConfig = sm.getConfiguration(); + securityConfig.addRole("openwireSender", "sender"); + securityConfig.addUser("openwireSender", "SeNdEr"); + //sender cannot receive + Role senderRole = new Role("sender", true, false, false, false, true, true, false); + + securityConfig.addRole("openwireReceiver", "receiver"); + securityConfig.addUser("openwireReceiver", "ReCeIvEr"); + //receiver cannot send + Role receiverRole = new Role("receiver", false, true, false, false, true, true, false); + + securityConfig.addRole("openwireGuest", "guest"); + securityConfig.addUser("openwireGuest", "GuEsT"); + + //guest cannot do anything + Role guestRole = new Role("guest", false, false, false, false, false, false, false); + + securityConfig.addRole("openwireDestinationManager", "manager"); + securityConfig.addUser("openwireDestinationManager", "DeStInAtIoN"); + + //guest cannot do anything + Role destRole = new Role("manager", false, false, false, false, true, true, false); + + Map> settings = server.getConfiguration().getSecurityRoles(); + if (settings == null) + { + settings = new HashMap>(); + server.getConfiguration().setSecurityRoles(settings); + } + Set anySet = settings.get("#"); + if (anySet == null) + { + anySet = new HashSet(); + settings.put("#", anySet); + } + anySet.add(senderRole); + anySet.add(receiverRole); + anySet.add(guestRole); + anySet.add(destRole); + } +/* no need to start jms server here + jmsServer = new JMSServerManagerImpl(server); + jmsServer.setContext(new InVMNamingContext()); + jmsServer.start(); +*/ + Set acceptors = serverConfig.getAcceptorConfigurations(); + Iterator iter = acceptors.iterator(); + + while (iter.hasNext()) + { + System.out.println(">: " + iter.next()); + } + server.start(); + +/* + registerConnectionFactory(); + mbeanServer = MBeanServerFactory.createMBeanServer(); +*/ + + ArtemisBrokerHelper.setBroker(this.bservice); + stopped = false; + + } + + @Override + public void stop() throws Exception + { + server.stop(); + testQueues.clear(); + stopped = true; + } + + public void makeSureQueueExists(String qname) throws Exception + { + synchronized (testQueues) + { + SimpleString coreQ = testQueues.get(qname); + if (coreQ == null) + { + coreQ = new SimpleString("jms.queue." + qname); + try + { + this.server.createQueue(coreQ, coreQ, null, false, false); + testQueues.put(qname, coreQ); + } + catch (ActiveMQQueueExistsException e) + { + //ignore + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/InVMNameParser.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/InVMNameParser.java new file mode 100644 index 0000000000..293cdb023e --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/InVMNameParser.java @@ -0,0 +1,74 @@ +/** + * 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.broker.artemiswrapper; + +import java.io.Serializable; +import java.util.Properties; + +import javax.naming.CompoundName; +import javax.naming.Name; +import javax.naming.NameParser; +import javax.naming.NamingException; + +/** + * @author Ovidiu Feodorov + * @version $Revision: 2868 $ + * + */ +public class InVMNameParser implements NameParser, Serializable +{ + // Constants ----------------------------------------------------- + + private static final long serialVersionUID = 2925203703371001031L; + + // Static -------------------------------------------------------- + + static Properties syntax; + + static + { + InVMNameParser.syntax = new Properties(); + InVMNameParser.syntax.put("jndi.syntax.direction", "left_to_right"); + InVMNameParser.syntax.put("jndi.syntax.ignorecase", "false"); + InVMNameParser.syntax.put("jndi.syntax.separator", "/"); + } + + // Attributes ---------------------------------------------------- + + // Constructors -------------------------------------------------- + + // Public -------------------------------------------------------- + + public static Properties getSyntax() + { + return InVMNameParser.syntax; + } + + public Name parse(final String name) throws NamingException + { + return new CompoundName(name, InVMNameParser.syntax); + } + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + // Inner classes ------------------------------------------------- + +} diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/InVMNamingContext.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/InVMNamingContext.java new file mode 100644 index 0000000000..017fa1775e --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/InVMNamingContext.java @@ -0,0 +1,370 @@ +/** + * 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.broker.artemiswrapper; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.RefAddr; +import javax.naming.Reference; + +public class InVMNamingContext implements Context, Serializable +{ + // Constants ----------------------------------------------------- + + private static final long serialVersionUID = 385743957345L; + + // Static -------------------------------------------------------- + + // Attributes ---------------------------------------------------- + + protected Map map; + + protected NameParser parser = new InVMNameParser(); + + private String nameInNamespace = ""; + + // Constructors -------------------------------------------------- + + public InVMNamingContext() + { + map = Collections.synchronizedMap(new HashMap()); + } + + public InVMNamingContext(final String nameInNamespace) + { + this(); + this.nameInNamespace = nameInNamespace; + } + + // Context implementation ---------------------------------------- + + public Object lookup(final Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public Object lookup(String name) throws NamingException + { + name = trimSlashes(name); + int i = name.indexOf("/"); + String tok = i == -1 ? name : name.substring(0, i); + Object value = map.get(tok); + if (value == null) + { + throw new NameNotFoundException("Name not found: " + tok); + } + if (value instanceof InVMNamingContext && i != -1) + { + return ((InVMNamingContext)value).lookup(name.substring(i)); + } + if (value instanceof Reference) + { + Reference ref = (Reference)value; + RefAddr refAddr = ref.get("nns"); + + // we only deal with references create by NonSerializableFactory + String key = (String)refAddr.getContent(); + return NonSerializableFactory.lookup(key); + } + else + { + return value; + } + } + + public void bind(final Name name, final Object obj) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public void bind(final String name, final Object obj) throws NamingException + { + internalBind(name, obj, false); + } + + public void rebind(final Name name, final Object obj) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public void rebind(final String name, final Object obj) throws NamingException + { + internalBind(name, obj, true); + } + + public void unbind(final Name name) throws NamingException + { + unbind(name.toString()); + } + + public void unbind(String name) throws NamingException + { + name = trimSlashes(name); + int i = name.indexOf("/"); + boolean terminal = i == -1; + if (terminal) + { + map.remove(name); + } + else + { + String tok = name.substring(0, i); + InVMNamingContext c = (InVMNamingContext)map.get(tok); + if (c == null) + { + throw new NameNotFoundException("Context not found: " + tok); + } + c.unbind(name.substring(i)); + } + } + + public void rename(final Name oldName, final Name newName) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public void rename(final String oldName, final String newName) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public NamingEnumeration list(final Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public NamingEnumeration list(final String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public NamingEnumeration listBindings(final Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public NamingEnumeration listBindings(String contextName) throws NamingException + { + contextName = trimSlashes(contextName); + if (!"".equals(contextName) && !".".equals(contextName)) + { + try + { + return ((InVMNamingContext)lookup(contextName)).listBindings(""); + } + catch (Throwable t) + { + throw new NamingException(t.getMessage()); + } + } + + List l = new ArrayList(); + for (Object element : map.keySet()) + { + String name = (String)element; + Object object = map.get(name); + l.add(new Binding(name, object)); + } + return new NamingEnumerationImpl(l.iterator()); + } + + public void destroySubcontext(final Name name) throws NamingException + { + destroySubcontext(name.toString()); + } + + public void destroySubcontext(final String name) throws NamingException + { + map.remove(trimSlashes(name)); + } + + public Context createSubcontext(final Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public Context createSubcontext(String name) throws NamingException + { + name = trimSlashes(name); + if (map.get(name) != null) + { + throw new NameAlreadyBoundException(name); + } + InVMNamingContext c = new InVMNamingContext(getNameInNamespace()); + map.put(name, c); + return c; + } + + public Object lookupLink(final Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public Object lookupLink(final String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public NameParser getNameParser(final Name name) throws NamingException + { + return getNameParser(name.toString()); + } + + public NameParser getNameParser(final String name) throws NamingException + { + return parser; + } + + public Name composeName(final Name name, final Name prefix) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public String composeName(final String name, final String prefix) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public Object addToEnvironment(final String propName, final Object propVal) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public Object removeFromEnvironment(final String propName) throws NamingException + { + throw new UnsupportedOperationException(); + } + + public Hashtable getEnvironment() throws NamingException + { + Hashtable env = new Hashtable(); + env.put("java.naming.factory.initial", "org.apache.activemq.artemis.jms.tests.tools.container.InVMInitialContextFactory"); + return env; + } + + public void close() throws NamingException + { + } + + public String getNameInNamespace() throws NamingException + { + return nameInNamespace; + } + + // Public -------------------------------------------------------- + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + private String trimSlashes(String s) + { + int i = 0; + while (true) + { + if (i == s.length() || s.charAt(i) != '/') + { + break; + } + i++; + } + s = s.substring(i); + i = s.length() - 1; + while (true) + { + if (i == -1 || s.charAt(i) != '/') + { + break; + } + i--; + } + return s.substring(0, i + 1); + } + + private void internalBind(String name, final Object obj, final boolean rebind) throws NamingException + { + name = trimSlashes(name); + int i = name.lastIndexOf("/"); + InVMNamingContext c = this; + if (i != -1) + { + String path = name.substring(0, i); + c = (InVMNamingContext)lookup(path); + } + name = name.substring(i + 1); + if (!rebind && c.map.get(name) != null) + { + throw new NameAlreadyBoundException(name); + } + c.map.put(name, obj); + } + + // Inner classes ------------------------------------------------- + + private class NamingEnumerationImpl implements NamingEnumeration + { + private final Iterator iterator; + + NamingEnumerationImpl(final Iterator bindingIterator) + { + iterator = bindingIterator; + } + + public void close() throws NamingException + { + throw new UnsupportedOperationException(); + } + + public boolean hasMore() throws NamingException + { + return iterator.hasNext(); + } + + public T next() throws NamingException + { + return iterator.next(); + } + + public boolean hasMoreElements() + { + return iterator.hasNext(); + } + + public T nextElement() + { + return iterator.next(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/NonSerializableFactory.java b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/NonSerializableFactory.java new file mode 100644 index 0000000000..0c39f130f3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/java/org/apache/activemq/broker/artemiswrapper/NonSerializableFactory.java @@ -0,0 +1,111 @@ +/** + * 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.broker.artemiswrapper; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.StringRefAddr; +import javax.naming.spi.ObjectFactory; + +//import org.jboss.util.naming.Util; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +/** + * used by the default context when running in embedded local configuration + * + * @author Andy Taylor + */ +public class NonSerializableFactory implements ObjectFactory +{ + + public NonSerializableFactory() + { + } +/* + public static void unbind(final Context ctx, final String strName) throws NamingException + { + Name name = ctx.getNameParser("").parse(strName); + int size = name.size(); + String atom = name.get(size - 1); + Context parentCtx = Util.createSubcontext(ctx, name.getPrefix(size - 1)); + String key = new StringBuilder().append(parentCtx.getNameInNamespace()).append("/").append(atom).toString(); + NonSerializableFactory.getWrapperMap().remove(key); + Util.unbind(ctx, strName); + } + + public static void rebind(final Context ctx, final String strName, final Object value) throws NamingException + { + Name name = ctx.getNameParser("").parse(strName); + int size = name.size(); + String atom = name.get(size - 1); + Context parentCtx = Util.createSubcontext(ctx, name.getPrefix(size - 1)); + String key = new StringBuilder().append(parentCtx.getNameInNamespace()).append("/").append(atom).toString(); + NonSerializableFactory.getWrapperMap().put(key, value); + String className = value.getClass().getName(); + String factory = NonSerializableFactory.class.getName(); + StringRefAddr addr = new StringRefAddr("nns", key); + Reference memoryRef = new Reference(className, addr, factory, null); + parentCtx.rebind(atom, memoryRef); + } + + public static void bind(final Context ctx, final String strName, final Object value) throws NamingException + { + Name name = ctx.getNameParser("").parse(strName); + int size = name.size(); + String atom = name.get(size - 1); + Context parentCtx = Util.createSubcontext(ctx, name.getPrefix(size - 1)); + String key = new StringBuilder().append(parentCtx.getNameInNamespace()).append("/").append(atom).toString(); + NonSerializableFactory.getWrapperMap().put(key, value); + String className = value.getClass().getName(); + String factory = NonSerializableFactory.class.getName(); + StringRefAddr addr = new StringRefAddr("nns", key); + Reference memoryRef = new Reference(className, addr, factory, null); + + parentCtx.bind(atom, memoryRef); + } +*/ + public static Object lookup(final String name) throws NamingException + { + if (NonSerializableFactory.getWrapperMap().get(name) == null) + { + throw new NamingException(name + " not found"); + } + return NonSerializableFactory.getWrapperMap().get(name); + } + + public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable env) throws Exception + { + Reference ref = (Reference) obj; + RefAddr addr = ref.get("nns"); + String key = (String) addr.getContent(); + return NonSerializableFactory.getWrapperMap().get(key); + } + + public static Map getWrapperMap() + { + return NonSerializableFactory.wrapperMap; + } + + private static Map wrapperMap = Collections.synchronizedMap(new HashMap()); +} diff --git a/tests/activemq5-unit-tests/src/main/resources/META-INF/services/org.apache.activemq.artemis.spi.core.protocol.ProtocolManagerFactory b/tests/activemq5-unit-tests/src/main/resources/META-INF/services/org.apache.activemq.artemis.spi.core.protocol.ProtocolManagerFactory new file mode 100644 index 0000000000..c76e40e79c --- /dev/null +++ b/tests/activemq5-unit-tests/src/main/resources/META-INF/services/org.apache.activemq.artemis.spi.core.protocol.ProtocolManagerFactory @@ -0,0 +1,2 @@ +org.apache.activemq.artemis.core.protocol.openwire.OpenWireProtocolManagerFactory + diff --git a/tests/activemq5-unit-tests/src/test/java/activemq-browse.properties b/tests/activemq5-unit-tests/src/test/java/activemq-browse.properties new file mode 100644 index 0000000000..36559c7877 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/activemq-browse.properties @@ -0,0 +1,61 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# Remote addresses for the other brokers in mesh + + +# 1a +1a.name=1a-nc +1a.uri=failover:(tcp://localhost:6106)?randomize=false +1a.transport=tcp://localhost:6106 +1a.jmx=1090 +1a.data=target/data/1a_store + +# 1b +1b.name=1b-nc +1b.uri=failover:(tcp://localhost:6107)?randomize=false +1b.transport=tcp://localhost:6107 +1b.jmx=1091 +1b.data=target/data/1b_store + +# 2a +2a.name=2a-nc +2a.uri=failover:(tcp://localhost:6108)?randomize=false +2a.transport=tcp://localhost:6108 +2a.jmx=1092 +2a.data=target/data/2a_store + +# 2b +2b.name=2b-nc +2b.uri=failover:(tcp://localhost:6109)?randomize=false +2b.transport=tcp://localhost:6109 +2b.jmx=1093 +2b.data=target/data/2b_store + +# 3a +3a.name=3a-nc +3a.uri=failover:(tcp://localhost:6110)?randomize=false +3a.transport=tcp://localhost:6110 +3a.jmx=1094 +3a.data=target/data/3a_store + +# 3b +3b.name=3b-nc +3b.uri=failover:(tcp://localhost:6111)?randomize=false +3b.transport=tcp://localhost:6111 +3b.jmx=1095 +3b.data=target/data/3b_store diff --git a/tests/activemq5-unit-tests/src/test/java/activemq-partition.xml b/tests/activemq5-unit-tests/src/test/java/activemq-partition.xml new file mode 100644 index 0000000000..4bb96f22a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/activemq-partition.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/activemq.xml b/tests/activemq5-unit-tests/src/test/java/activemq.xml new file mode 100644 index 0000000000..eb49ca08d0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/activemq.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/client.keystore b/tests/activemq5-unit-tests/src/test/java/client.keystore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/credentials.properties b/tests/activemq5-unit-tests/src/test/java/credentials.properties new file mode 100644 index 0000000000..86f719940f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/credentials.properties @@ -0,0 +1,24 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# Defines credentials that will be used by components (like web console) to access the broker + +activemq.username=system +#activemq.password=manager +activemq.password=ENC(mYRkg+4Q4hua1kvpCCI2hg==) +#guest.password=password +guest.password=ENC(Cf3Jf3tM+UrSOoaKU50od5CuBa8rxjoL) \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/dummy.keystore b/tests/activemq5-unit-tests/src/test/java/dummy.keystore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/jmx.access b/tests/activemq5-unit-tests/src/test/java/jmx.access new file mode 100644 index 0000000000..4625b7dea4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/jmx.access @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +admin readwrite \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/jmx.password b/tests/activemq5-unit-tests/src/test/java/jmx.password new file mode 100644 index 0000000000..053aa659f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/jmx.password @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +admin activemq \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/jndi.properties b/tests/activemq5-unit-tests/src/test/java/jndi.properties new file mode 100644 index 0000000000..d627de9c34 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/jndi.properties @@ -0,0 +1,38 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# START SNIPPET: jndi + +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory + +# use the following property to configure the default connector +java.naming.provider.url = vm://localhost + +# use the following property to specify the JNDI name the connection factory +# should appear as. +#connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry + +# register some queues in JNDI using the form +# queue.[jndiName] = [physicalName] +queue.MyQueue = example.MyQueue + + +# register some topics in JNDI using the form +# topic.[jndiName] = [physicalName] +topic.MyTopic = example.MyTopic + +# END SNIPPET: jndi diff --git a/tests/activemq5-unit-tests/src/test/java/log4j.properties b/tests/activemq5-unit-tests/src/test/java/log4j.properties new file mode 100644 index 0000000000..4704dbc325 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/log4j.properties @@ -0,0 +1,46 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# +# The logging properties used during tests.. +# +log4j.rootLogger=INFO, out, stdout + +#log4j.logger.org.apache.activemq.broker.scheduler=DEBUG +#log4j.logger.org.apache.activemq.store.kahadb.scheduler=DEBUG +#log4j.logger.org.apache.activemq.network.DemandForwardingBridgeSupport=DEBUG +#log4j.logger.org.apache.activemq.transport.failover=TRACE +#log4j.logger.org.apache.activemq.store.jdbc=TRACE +#log4j.logger.org.apache.activemq.store.kahadb=TRACE +#log4j.logger.org.apache.activemq.broker.region.cursors.AbstractStoreCursor=DEBUG +#log4j.logger.org.apache.activemq.store.jdbc.JDBCMessageStore=DEBUG +#log4j.logger.org.apache.activemq.store.kahadb.disk.journal=DEBUG +#log4j.logger.org.apache.activemq.store.kahadb.AbstractKahaDBStore=DEBUG + +# CONSOLE appender not used by default +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n +#log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %-10.10X{activemq.broker} %-20.20X{activemq.connector} %-10.10X{activemq.destination} - %m%n + +# File appender +log4j.appender.out=org.apache.log4j.FileAppender +log4j.appender.out.layout=org.apache.log4j.PatternLayout +log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n +#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %-10.10X{activemq.broker} %-20.20X{activemq.connector} %-10.10X{activemq.destination} - %m%n +log4j.appender.out.file=target/activemq-test.log +log4j.appender.out.append=true diff --git a/tests/activemq5-unit-tests/src/test/java/login.config b/tests/activemq5-unit-tests/src/test/java/login.config new file mode 100644 index 0000000000..1f5f77c805 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/login.config @@ -0,0 +1,87 @@ +/** + * 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. + */ +activemq-domain { + org.apache.activemq.jaas.PropertiesLoginModule required + debug=true + org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties"; +}; + +activemq-guest-domain { + org.apache.activemq.jaas.PropertiesLoginModule sufficient + debug=true + org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties"; + org.apache.activemq.jaas.GuestLoginModule sufficient + debug=true + org.apache.activemq.jaas.guest.user="guest" + org.apache.activemq.jaas.guest.group="guests"; +}; + +activemq-guest-when-no-creds-only-domain { + org.apache.activemq.jaas.GuestLoginModule sufficient + debug=true + credentialsInvalidate=true + org.apache.activemq.jaas.guest.user="guest" + org.apache.activemq.jaas.guest.group="guests"; + + org.apache.activemq.jaas.PropertiesLoginModule requisite + debug=true + org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties"; +}; + +cert-login { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; + +}; + +broker1 { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users1.properties" + org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; +}; + +broker2 { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users2.properties" + org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; +}; + +LDAPLogin { + org.apache.activemq.jaas.LDAPLoginModule required + debug=true + initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory + connectionURL="ldap://localhost:1024" + connectionUsername="uid=admin,ou=system" + connectionPassword=secret + connectionProtocol=s + authentication=simple + userBase="ou=User,ou=ActiveMQ,ou=system" + userSearchMatching="(uid={0})" + userSearchSubtree=false + roleBase="ou=Group,ou=ActiveMQ,ou=system" + roleName=cn + roleSearchMatching="(uid={1})" + roleSearchSubtree=true + ; +}; \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/openwire-control/org.apache.activemq.openwire.BrokerInfoData.bin b/tests/activemq5-unit-tests/src/test/java/openwire-control/org.apache.activemq.openwire.BrokerInfoData.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/openwire-control/org.apache.activemq.openwire.WireFormatInfoData.bin b/tests/activemq5-unit-tests/src/test/java/openwire-control/org.apache.activemq.openwire.WireFormatInfoData.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQConnectionFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQConnectionFactoryTest.java new file mode 100644 index 0000000000..353f1d3262 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQConnectionFactoryTest.java @@ -0,0 +1,261 @@ +/** + * 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; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ActiveMQConnectionFactoryTest extends CombinationTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ActiveMQConnectionFactoryTest.class); + + private ActiveMQConnection connection; + private BrokerService broker; + + public void testUseURIToSetUseClientIDPrefixOnConnectionFactory() throws URISyntaxException, JMSException { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory( + "vm://localhost?jms.clientIDPrefix=Cheese"); + assertEquals("Cheese", cf.getClientIDPrefix()); + + connection = (ActiveMQConnection)cf.createConnection(); + connection.start(); + + String clientID = connection.getClientID(); + LOG.info("Got client ID: " + clientID); + + assertTrue("should start with Cheese! but was: " + clientID, clientID.startsWith("Cheese")); + } + + @Override + public void tearDown() throws Exception { + // Try our best to close any previously opend connection. + try { + connection.close(); + } catch (Throwable ignore) { + } + // Try our best to stop any previously started broker. + try { + broker.stop(); + } catch (Throwable ignore) { + } + } + + public void testUseURIToSetOptionsOnConnectionFactory() throws URISyntaxException, JMSException { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?jms.useAsyncSend=true"); + assertTrue(cf.isUseAsyncSend()); + // the broker url have been adjusted. + assertEquals("vm://localhost", cf.getBrokerURL()); + + cf = new ActiveMQConnectionFactory("vm://localhost?jms.useAsyncSend=false"); + assertFalse(cf.isUseAsyncSend()); + // the broker url have been adjusted. + assertEquals("vm://localhost", cf.getBrokerURL()); + + cf = new ActiveMQConnectionFactory("vm:(broker:()/localhost)?jms.useAsyncSend=true"); + assertTrue(cf.isUseAsyncSend()); + // the broker url have been adjusted. + assertEquals("vm:(broker:()/localhost)", cf.getBrokerURL()); + + cf = new ActiveMQConnectionFactory("vm://localhost?jms.auditDepth=5000"); + assertEquals(5000, cf.getAuditDepth()); + } + + public void testUseURIToConfigureRedeliveryPolicy() throws URISyntaxException, JMSException { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory( + "vm://localhost?jms.redeliveryPolicy.maximumRedeliveries=2"); + assertEquals("connection redeliveries", 2, cf.getRedeliveryPolicy().getMaximumRedeliveries()); + + ActiveMQConnection connection = (ActiveMQConnection)cf.createConnection(); + assertEquals("connection redeliveries", 2, connection.getRedeliveryPolicy().getMaximumRedeliveries()); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer)session.createConsumer(session + .createQueue("FOO.BAR")); + assertEquals("consumer redeliveries", 2, consumer.getRedeliveryPolicy().getMaximumRedeliveries()); + connection.close(); + } + + public void testCreateVMConnectionWithEmbdeddBroker() throws URISyntaxException, JMSException { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://myBroker2?broker.persistent=false"); + // Make sure the broker is not created until the connection is + // instantiated. + assertNull(BrokerRegistry.getInstance().lookup("myBroker2")); + connection = (ActiveMQConnection)cf.createConnection(); + // This should create the connection. + assertNotNull(connection); + // Verify the broker was created. + assertNotNull(BrokerRegistry.getInstance().lookup("myBroker2")); + + connection.close(); + + // Verify the broker was destroyed. + assertNull(BrokerRegistry.getInstance().lookup("myBroker2")); + } + + public void testGetBrokerName() throws URISyntaxException, JMSException { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = (ActiveMQConnection)cf.createConnection(); + connection.start(); + + String brokerName = connection.getBrokerName(); + LOG.info("Got broker name: " + brokerName); + + assertNotNull("No broker name available!", brokerName); + } + + public void testCreateTcpConnectionUsingAllocatedPort() throws Exception { + assertCreateConnection("tcp://localhost:0?wireFormat.tcpNoDelayEnabled=true"); + } + + public void testCreateTcpConnectionUsingKnownPort() throws Exception { + assertCreateConnection("tcp://localhost:61610?wireFormat.tcpNoDelayEnabled=true"); + } + + public void testCreateTcpConnectionUsingKnownLocalPort() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.addConnector("tcp://localhost:61610?wireFormat.tcpNoDelayEnabled=true"); + broker.start(); + + // This should create the connection. + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61610/localhost:51610"); + connection = (ActiveMQConnection)cf.createConnection(); + assertNotNull(connection); + + connection.close(); + + broker.stop(); + } + + public void testConnectionFailsToConnectToVMBrokerThatIsNotRunning() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?create=false"); + try { + factory.createConnection(); + fail("Expected connection failure."); + } catch (JMSException e) { + } + } + + public void testFactorySerializable() throws Exception { + String clientID = "TestClientID"; + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); + cf.setClientID(clientID); + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream objectsOut = new ObjectOutputStream(bytesOut); + objectsOut.writeObject(cf); + objectsOut.flush(); + byte[] data = bytesOut.toByteArray(); + ByteArrayInputStream bytesIn = new ByteArrayInputStream(data); + ObjectInputStream objectsIn = new ObjectInputStream(bytesIn); + cf = (ActiveMQConnectionFactory)objectsIn.readObject(); + assertEquals(cf.getClientID(), clientID); + } + + public void testSetExceptionListener() throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = (ActiveMQConnection)cf.createConnection(); + assertNull(connection.getExceptionListener()); + + ExceptionListener exListener = new ExceptionListener() { + @Override + public void onException(JMSException arg0) { + } + }; + cf.setExceptionListener(exListener); + connection.close(); + + connection = (ActiveMQConnection)cf.createConnection(); + assertNotNull(connection.getExceptionListener()); + assertEquals(exListener, connection.getExceptionListener()); + connection.close(); + + connection = (ActiveMQConnection)cf.createConnection(); + assertEquals(exListener, connection.getExceptionListener()); + + assertEquals(exListener, cf.getExceptionListener()); + connection.close(); + + } + + + public void testSetClientInternalExceptionListener() throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = (ActiveMQConnection)cf.createConnection(); + assertNull(connection.getClientInternalExceptionListener()); + + ClientInternalExceptionListener listener = new ClientInternalExceptionListener() { + @Override + public void onException(Throwable exception) { + } + }; + connection.setClientInternalExceptionListener(listener); + cf.setClientInternalExceptionListener(listener); + connection.close(); + + connection = (ActiveMQConnection)cf.createConnection(); + assertNotNull(connection.getClientInternalExceptionListener()); + assertEquals(listener, connection.getClientInternalExceptionListener()); + connection.close(); + + connection = (ActiveMQConnection)cf.createConnection(); + assertEquals(listener, connection.getClientInternalExceptionListener()); + assertEquals(listener, cf.getClientInternalExceptionListener()); + connection.close(); + + } + + protected void assertCreateConnection(String uri) throws Exception { + // Start up a broker with a tcp connector. + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + TransportConnector connector = broker.addConnector(uri); + broker.start(); + + URI temp = new URI(uri); + // URI connectURI = connector.getServer().getConnectURI(); + // TODO this sometimes fails when using the actual local host name + URI currentURI = new URI(connector.getPublishableConnectString()); + + // sometimes the actual host name doesn't work in this test case + // e.g. on OS X so lets use the original details but just use the actual + // port + URI connectURI = new URI(temp.getScheme(), temp.getUserInfo(), temp.getHost(), currentURI.getPort(), + temp.getPath(), temp.getQuery(), temp.getFragment()); + + LOG.info("connection URI is: " + connectURI); + + // This should create the connection. + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(connectURI); + connection = (ActiveMQConnection)cf.createConnection(); + assertNotNull(connection); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQInputStreamTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQInputStreamTest.java new file mode 100644 index 0000000000..77f422e159 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQInputStreamTest.java @@ -0,0 +1,145 @@ +/* + * 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; + +import java.io.InputStream; +import java.io.OutputStream; + +import javax.jms.Queue; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Deprecated +public class ActiveMQInputStreamTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ActiveMQInputStreamTest.class); + + private static final String BROKER_URL = "tcp://localhost:0"; + private static final String DESTINATION = "destination"; + private static final int STREAM_LENGTH = 64 * 1024 + 0; // change 0 to 1 to make it not crash + + private BrokerService broker; + private String connectionUri; + + @Override + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setUseJmx(false); + broker.setPersistent(false); + broker.setDestinations(new ActiveMQDestination[] { + ActiveMQDestination.createDestination(DESTINATION, ActiveMQDestination.QUEUE_TYPE), + }); + broker.addConnector(BROKER_URL); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + @Override + public void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + public void testInputStreamSetSyncSendOption() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(DESTINATION + "?producer.alwaysSyncSend=true"); + + OutputStream out = null; + try { + out = connection.createOutputStream(destination); + + assertTrue(((ActiveMQOutputStream)out).isAlwaysSyncSend()); + + LOG.debug("writing..."); + for (int i = 0; i < STREAM_LENGTH; ++i) { + out.write(0); + } + LOG.debug("wrote " + STREAM_LENGTH + " bytes"); + } finally { + if (out != null) { + out.close(); + } + } + + InputStream in = null; + try { + in = connection.createInputStream(destination); + LOG.debug("reading..."); + int count = 0; + while (-1 != in.read()) { + ++count; + } + LOG.debug("read " + count + " bytes"); + } finally { + if (in != null) { + in.close(); + } + } + + connection.close(); + } + + public void testInputStreamMatchesDefaultChuckSize() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(DESTINATION); + + OutputStream out = null; + try { + out = connection.createOutputStream(destination); + LOG.debug("writing..."); + for (int i = 0; i < STREAM_LENGTH; ++i) { + out.write(0); + } + LOG.debug("wrote " + STREAM_LENGTH + " bytes"); + } finally { + if (out != null) { + out.close(); + } + } + + InputStream in = null; + try { + in = connection.createInputStream(destination); + LOG.debug("reading..."); + int count = 0; + while (-1 != in.read()) { + ++count; + } + LOG.debug("read " + count + " bytes"); + } finally { + if (in != null) { + in.close(); + } + } + + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQMessageAuditTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQMessageAuditTest.java new file mode 100644 index 0000000000..af18084683 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQMessageAuditTest.java @@ -0,0 +1,186 @@ +/** + * 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; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.List; +import junit.framework.TestCase; +import org.apache.activemq.broker.region.MessageReference; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.util.IdGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ActiveMQMessageAuditTest + * + * + */ +public class ActiveMQMessageAuditTest extends TestCase { + + static final Logger LOG = LoggerFactory.getLogger(ActiveMQMessageAuditTest.class); + + /** + * Constructor for ActiveMQMessageAuditTest. + * + * @param name + */ + public ActiveMQMessageAuditTest(String name) { + super(name); + } + + public static void main(String[] args) { + } + + protected void setUp() throws Exception { + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * test case for isDuplicate + */ + public void testIsDuplicateString() { + int count = 10000; + ActiveMQMessageAudit audit = new ActiveMQMessageAudit(); + IdGenerator idGen = new IdGenerator(); + // add to a list + List list = new ArrayList(); + for (int i = 0; i < count; i++) { + String id = idGen.generateId(); + list.add(id); + assertFalse(audit.isDuplicate(id)); + } + List windowList = list.subList(list.size() -1 -audit.getAuditDepth(), list.size() -1); + for (String id : windowList) { + assertTrue("duplicate, id:" + id, audit.isDuplicate(id)); + } + } + + public void testIsDuplicateMessageReference() { + int count = 10000; + ActiveMQMessageAudit audit = new ActiveMQMessageAudit(); + // add to a list + List list = new ArrayList(); + for (int i = 0; i < count; i++) { + ProducerId pid = new ProducerId(); + pid.setConnectionId("test"); + pid.setSessionId(0); + pid.setValue(1); + MessageId id = new MessageId(); + id.setProducerId(pid); + id.setProducerSequenceId(i); + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setMessageId(id); + list.add(msg); + assertFalse(audit.isDuplicate(msg.getMessageId())); + } + List windowList = list.subList(list.size() -1 -audit.getAuditDepth(), list.size() -1); + for (MessageReference msg : windowList) { + assertTrue("duplicate msg:" + msg, audit.isDuplicate(msg)); + } + } + + public void testIsInOrderString() { + int count = 10000; + ActiveMQMessageAudit audit = new ActiveMQMessageAudit(); + IdGenerator idGen = new IdGenerator(); + // add to a list + List list = new ArrayList(); + for (int i = 0; i < count; i++) { + String id = idGen.generateId(); + if (i==0) { + assertFalse(audit.isDuplicate(id)); + assertTrue(audit.isInOrder(id)); + } + if (i > 1 && i%2 != 0) { + list.add(id); + } + + } + for (String id : list) { + assertFalse(audit.isInOrder(id)); + assertFalse(audit.isDuplicate(id)); + } + } + + public void testSerialization() throws Exception { + ActiveMQMessageAuditNoSync audit = new ActiveMQMessageAuditNoSync(); + + byte[] bytes = serialize(audit); + LOG.debug("Length: " + bytes.length); + audit = recover(bytes); + + List list = new ArrayList(); + + for (int j = 0; j < 1000; j++) { + ProducerId pid = new ProducerId(); + pid.setConnectionId("test"); + pid.setSessionId(0); + pid.setValue(j); + LOG.debug("producer " + j); + + for (int i = 0; i < 1000; i++) { + MessageId id = new MessageId(); + id.setProducerId(pid); + id.setProducerSequenceId(i); + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setMessageId(id); + list.add(msg); + assertFalse(audit.isDuplicate(msg.getMessageId().toString())); + + if (i % 100 == 0) { + bytes = serialize(audit); + LOG.debug("Length: " + bytes.length); + audit = recover(bytes); + } + + if (i % 250 == 0) { + for (MessageReference message : list) { + audit.rollback(message.getMessageId().toString()); + } + list.clear(); + bytes = serialize(audit); + LOG.debug("Length: " + bytes.length); + audit = recover(bytes); + } + } + } + } + + protected byte[] serialize(ActiveMQMessageAuditNoSync audit) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(baos); + oout.writeObject(audit); + oout.flush(); + return baos.toByteArray(); + } + + protected ActiveMQMessageAuditNoSync recover(byte[] bytes) throws Exception { + ObjectInputStream objectIn = new ObjectInputStream(new ByteArrayInputStream(bytes)); + return (ActiveMQMessageAuditNoSync)objectIn.readObject(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQSslConnectionFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQSslConnectionFactoryTest.java new file mode 100644 index 0000000000..5d1ec8034e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQSslConnectionFactoryTest.java @@ -0,0 +1,262 @@ +/** + * 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; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyStore; +import java.security.SecureRandom; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.SslBrokerService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class ActiveMQSslConnectionFactoryTest extends CombinationTestSupport { + private static final Log LOG = LogFactory.getLog(ActiveMQSslConnectionFactoryTest.class); + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/server.keystore"; + public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore"; + + private ActiveMQConnection connection; + private BrokerService broker; + + @Override + protected void tearDown() throws Exception { + // Try our best to close any previously opend connection. + try { + connection.close(); + } catch (Throwable ignore) { + } + // Try our best to stop any previously started broker. + try { + broker.stop(); + } catch (Throwable ignore) { + } + } + + public void testCreateTcpConnectionUsingKnownPort() throws Exception { + // Control case: check that the factory can create an ordinary (non-ssl) connection. + broker = createBroker("tcp://localhost:61610?wireFormat.tcpNoDelayEnabled=true"); + + // This should create the connection. + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory("tcp://localhost:61610?wireFormat.tcpNoDelayEnabled=true"); + connection = (ActiveMQConnection)cf.createConnection(); + assertNotNull(connection); + connection.start(); + connection.stop(); + brokerStop(); + } + + public void testCreateFailoverTcpConnectionUsingKnownPort() throws Exception { + // Control case: check that the factory can create an ordinary (non-ssl) connection. + broker = createBroker("tcp://localhost:61610?wireFormat.tcpNoDelayEnabled=true"); + + // This should create the connection. + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory("failover:(tcp://localhost:61610?wireFormat.tcpNoDelayEnabled=true)"); + connection = (ActiveMQConnection)cf.createConnection(); + assertNotNull(connection); + connection.start(); + connection.stop(); + brokerStop(); + } + + public void testCreateSslConnection() throws Exception { + // Create SSL/TLS connection with trusted cert from truststore. + String sslUri = "ssl://localhost:61611"; + broker = createSslBroker(sslUri); + assertNotNull(broker); + + // This should create the connection. + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory(sslUri); + cf.setTrustStore("server.keystore"); + cf.setTrustStorePassword("password"); + connection = (ActiveMQConnection)cf.createConnection(); + LOG.info("Created client connection"); + assertNotNull(connection); + connection.start(); + connection.stop(); + brokerStop(); + } + + public void testFailoverSslConnection() throws Exception { + // Create SSL/TLS connection with trusted cert from truststore. + String sslUri = "ssl://localhost:61611"; + broker = createSslBroker(sslUri); + assertNotNull(broker); + + // This should create the connection. + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory("failover:(" + sslUri + ")?maxReconnectAttempts=4"); + cf.setTrustStore("server.keystore"); + cf.setTrustStorePassword("password"); + connection = (ActiveMQConnection)cf.createConnection(); + LOG.info("Created client connection"); + assertNotNull(connection); + connection.start(); + connection.stop(); + + brokerStop(); + } + + public void testFailoverSslConnectionWithKeyAndTrustManagers() throws Exception { + String sslUri = "ssl://localhost:61611"; + broker = createSslBroker(sslUri); + assertNotNull(broker); + + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory("failover:(" + sslUri + ")?maxReconnectAttempts=4"); + cf.setKeyAndTrustManagers(getKeyManager(), getTrustManager(), new SecureRandom()); + connection = (ActiveMQConnection)cf.createConnection(); + LOG.info("Created client connection"); + assertNotNull(connection); + connection.start(); + connection.stop(); + + brokerStop(); + } + + public void testNegativeCreateSslConnectionWithWrongPassword() throws Exception { + // Create SSL/TLS connection with trusted cert from truststore. + String sslUri = "ssl://localhost:61611"; + broker = createSslBroker(sslUri); + assertNotNull(broker); + + // This should FAIL to connect, due to wrong password. + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory(sslUri); + cf.setTrustStore("server.keystore"); + cf.setTrustStorePassword("wrongPassword"); + try { + connection = (ActiveMQConnection)cf.createConnection(); + } + catch (javax.jms.JMSException ignore) { + // Expected exception + LOG.info("Expected java.io.Exception [" + ignore + "]"); + } + assertNull(connection); + + brokerStop(); + } + + public void testNegativeCreateSslConnectionWithWrongCert() throws Exception { + // Create SSL/TLS connection with trusted cert from truststore. + String sslUri = "ssl://localhost:61611"; + broker = createSslBroker(sslUri); + assertNotNull(broker); + + // This should FAIL to connect, due to wrong password. + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory(sslUri); + cf.setTrustStore("dummy.keystore"); + cf.setTrustStorePassword("password"); + try { + connection = (ActiveMQConnection)cf.createConnection(); + } + catch (javax.jms.JMSException ignore) { + // Expected exception + LOG.info("Expected SSLHandshakeException [" + ignore + "]"); + } + assertNull(connection); + + brokerStop(); + } + + protected BrokerService createBroker(String uri) throws Exception { + // Start up a broker with a tcp connector. + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + service.addConnector(uri); + service.start(); + + return service; + } + + protected BrokerService createSslBroker(String uri) throws Exception { + + // http://java.sun.com/javase/javaseforbusiness/docs/TLSReadme.html + // work around: javax.net.ssl.SSLHandshakeException: renegotiation is not allowed + //System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true"); + + SslBrokerService service = new SslBrokerService(); + service.setPersistent(false); + + service.setupSsl(KEYSTORE_TYPE, PASSWORD, SERVER_KEYSTORE); + + service.start(); + + return service; + } + + protected void brokerStop() throws Exception { + broker.stop(); + } + + public static TrustManager[] getTrustManager() throws Exception { + TrustManager[] trustStoreManagers = null; + KeyStore trustedCertStore = KeyStore.getInstance(ActiveMQSslConnectionFactoryTest.KEYSTORE_TYPE); + + trustedCertStore.load(new FileInputStream(ActiveMQSslConnectionFactoryTest.TRUST_KEYSTORE), null); + TrustManagerFactory tmf = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + + tmf.init(trustedCertStore); + trustStoreManagers = tmf.getTrustManagers(); + return trustStoreManagers; + } + + public static KeyManager[] getKeyManager() throws Exception { + KeyManagerFactory kmf = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + KeyStore ks = KeyStore.getInstance(ActiveMQSslConnectionFactoryTest.KEYSTORE_TYPE); + KeyManager[] keystoreManagers = null; + + byte[] sslCert = loadClientCredential(ActiveMQSslConnectionFactoryTest.SERVER_KEYSTORE); + + + if (sslCert != null && sslCert.length > 0) { + ByteArrayInputStream bin = new ByteArrayInputStream(sslCert); + ks.load(bin, ActiveMQSslConnectionFactoryTest.PASSWORD.toCharArray()); + kmf.init(ks, ActiveMQSslConnectionFactoryTest.PASSWORD.toCharArray()); + keystoreManagers = kmf.getKeyManagers(); + } + return keystoreManagers; + } + + private static byte[] loadClientCredential(String fileName) throws IOException { + if (fileName == null) { + return null; + } + FileInputStream in = new FileInputStream(fileName); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buf = new byte[512]; + int i = in.read(buf); + while (i > 0) { + out.write(buf, 0, i); + i = in.read(buf); + } + in.close(); + return out.toByteArray(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQXAConnectionFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQXAConnectionFactoryTest.java new file mode 100644 index 0000000000..4b89851ffb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ActiveMQXAConnectionFactoryTest.java @@ -0,0 +1,584 @@ +/** + * 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; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; +import javax.jms.XAConnection; +import javax.jms.XAQueueConnection; +import javax.jms.XASession; +import javax.jms.XATopicConnection; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransactionBroker; +import org.apache.activemq.broker.TransportConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.TransactionInfo; +import org.apache.activemq.command.XATransactionId; +import org.apache.activemq.management.JMSConnectionStatsImpl; +import org.apache.activemq.transport.failover.FailoverTransport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ActiveMQXAConnectionFactoryTest extends CombinationTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ActiveMQXAConnectionFactoryTest.class); + long txGenerator = System.currentTimeMillis(); + private ActiveMQConnection connection; + private BrokerService broker; + + @Override + public void tearDown() throws Exception { + // Try our best to close any previously opend connection. + try { + connection.close(); + } catch (Throwable ignore) { + } + // Try our best to stop any previously started broker. + try { + broker.stop(); + } catch (Throwable ignore) { + } + } + + public void testCopy() throws URISyntaxException, JMSException { + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory("vm://localhost?"); + ActiveMQConnectionFactory copy = cf.copy(); + assertTrue("Should be an ActiveMQXAConnectionFactory", copy instanceof ActiveMQXAConnectionFactory); + } + + public void testUseURIToSetOptionsOnConnectionFactory() throws URISyntaxException, JMSException { + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory( + "vm://localhost?jms.useAsyncSend=true"); + assertTrue(cf.isUseAsyncSend()); + // the broker url have been adjusted. + assertEquals("vm://localhost", cf.getBrokerURL()); + + cf = new ActiveMQXAConnectionFactory("vm://localhost?jms.useAsyncSend=false"); + assertFalse(cf.isUseAsyncSend()); + // the broker url have been adjusted. + assertEquals("vm://localhost", cf.getBrokerURL()); + + cf = new ActiveMQXAConnectionFactory("vm:(broker:()/localhost)?jms.useAsyncSend=true"); + assertTrue(cf.isUseAsyncSend()); + // the broker url have been adjusted. + assertEquals("vm:(broker:()/localhost)", cf.getBrokerURL()); + + cf = new ActiveMQXAConnectionFactory( + "vm://localhost?jms.redeliveryPolicy.maximumRedeliveries=10&" + + "jms.redeliveryPolicy.initialRedeliveryDelay=10000&" + + "jms.redeliveryPolicy.redeliveryDelay=10000&" + + "jms.redeliveryPolicy.useExponentialBackOff=true&" + + "jms.redeliveryPolicy.backOffMultiplier=2"); + assertEquals(10, cf.getRedeliveryPolicy().getMaximumRedeliveries()); + assertEquals(10000, cf.getRedeliveryPolicy().getInitialRedeliveryDelay()); + assertEquals(10000, cf.getRedeliveryPolicy().getRedeliveryDelay()); + assertEquals(true, cf.getRedeliveryPolicy().isUseExponentialBackOff()); + assertEquals(2.0, cf.getRedeliveryPolicy().getBackOffMultiplier(), 0.1); + + // the broker url have been adjusted. + assertEquals("vm://localhost", cf.getBrokerURL()); + } + + public void testCreateVMConnectionWithEmbdeddBroker() throws URISyntaxException, JMSException { + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory("vm://myBroker?broker.persistent=false"); + // Make sure the broker is not created until the connection is + // instantiated. + assertNull(BrokerRegistry.getInstance().lookup("myBroker")); + connection = (ActiveMQConnection) cf.createConnection(); + // This should create the connection. + assertNotNull(connection); + // Verify the broker was created. + assertNotNull(BrokerRegistry.getInstance().lookup("myBroker")); + connection.close(); + // Verify the broker was destroyed. + assertNull(BrokerRegistry.getInstance().lookup("myBroker")); + + connection.close(); + } + + public void testGetBrokerName() throws URISyntaxException, JMSException { + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + connection = (ActiveMQConnection)cf.createConnection(); + connection.start(); + + String brokerName = connection.getBrokerName(); + LOG.info("Got broker name: " + brokerName); + + assertNotNull("No broker name available!", brokerName); + connection.close(); + } + + public void testCreateTcpConnectionUsingAllocatedPort() throws Exception { + assertCreateConnection("tcp://localhost:0?wireFormat.tcpNoDelayEnabled=true"); + } + + public void testCreateTcpConnectionUsingKnownPort() throws Exception { + assertCreateConnection("tcp://localhost:61610?wireFormat.tcpNoDelayEnabled=true"); + } + + public void testIsSameRM() throws URISyntaxException, JMSException, XAException { + + XAConnection connection1 = null; + XAConnection connection2 = null; + try { + ActiveMQXAConnectionFactory cf1 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + connection1 = (XAConnection)cf1.createConnection(); + XASession session1 = connection1.createXASession(); + XAResource resource1 = session1.getXAResource(); + + ActiveMQXAConnectionFactory cf2 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + connection2 = (XAConnection)cf2.createConnection(); + XASession session2 = connection2.createXASession(); + XAResource resource2 = session2.getXAResource(); + + assertTrue(resource1.isSameRM(resource2)); + session1.close(); + session2.close(); + } finally { + if (connection1 != null) { + try { + connection1.close(); + } catch (Exception e) { + // ignore + } + } + if (connection2 != null) { + try { + connection2.close(); + } catch (Exception e) { + // ignore + } + } + } + } + + public void testIsSameRMOverride() throws URISyntaxException, JMSException, XAException { + + XAConnection connection1 = null; + XAConnection connection2 = null; + try { + ActiveMQXAConnectionFactory cf1 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false&jms.rmIdFromConnectionId=true"); + connection1 = (XAConnection)cf1.createConnection(); + XASession session1 = connection1.createXASession(); + XAResource resource1 = session1.getXAResource(); + + ActiveMQXAConnectionFactory cf2 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + connection2 = (XAConnection)cf2.createConnection(); + XASession session2 = connection2.createXASession(); + XAResource resource2 = session2.getXAResource(); + + assertFalse(resource1.isSameRM(resource2)); + + // ensure identity is preserved + XASession session1a = connection1.createXASession(); + assertTrue(resource1.isSameRM(session1a.getXAResource())); + session1.close(); + session2.close(); + } finally { + if (connection1 != null) { + try { + connection1.close(); + } catch (Exception e) { + // ignore + } + } + if (connection2 != null) { + try { + connection2.close(); + } catch (Exception e) { + // ignore + } + } + } + } + + public void testVanilaTransactionalProduceReceive() throws Exception { + + XAConnection connection1 = null; + try { + ActiveMQXAConnectionFactory cf1 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + connection1 = (XAConnection)cf1.createConnection(); + connection1.start(); + XASession session = connection1.createXASession(); + XAResource resource = session.getXAResource(); + Destination dest = new ActiveMQQueue(getName()); + + // publish a message + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + MessageProducer producer = session.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setText(getName()); + producer.send(message); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + session.close(); + + session = connection1.createXASession(); + MessageConsumer consumer = session.createConsumer(dest); + tid = createXid(); + resource = session.getXAResource(); + resource.start(tid, XAResource.TMNOFLAGS); + TextMessage receivedMessage = (TextMessage) consumer.receive(1000); + assertNotNull(receivedMessage); + assertEquals(getName(), receivedMessage.getText()); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + session.close(); + + } finally { + if (connection1 != null) { + try { + connection1.close(); + } catch (Exception e) { + // ignore + } + } + } + } + + public void testConsumerCloseTransactionalSendReceive() throws Exception { + + ActiveMQXAConnectionFactory cf1 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + XAConnection connection1 = (XAConnection)cf1.createConnection(); + connection1.start(); + XASession session = connection1.createXASession(); + XAResource resource = session.getXAResource(); + Destination dest = new ActiveMQQueue(getName()); + + // publish a message + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + MessageProducer producer = session.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setText(getName()); + producer.send(message); + producer.close(); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + session.close(); + + session = connection1.createXASession(); + MessageConsumer consumer = session.createConsumer(dest); + tid = createXid(); + resource = session.getXAResource(); + resource.start(tid, XAResource.TMNOFLAGS); + TextMessage receivedMessage = (TextMessage) consumer.receive(1000); + consumer.close(); + assertNotNull(receivedMessage); + assertEquals(getName(), receivedMessage.getText()); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + + session = connection1.createXASession(); + consumer = session.createConsumer(dest); + tid = createXid(); + resource = session.getXAResource(); + resource.start(tid, XAResource.TMNOFLAGS); + assertNull(consumer.receive(1000)); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + + } + + public void testSessionCloseTransactionalSendReceive() throws Exception { + + ActiveMQXAConnectionFactory cf1 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + XAConnection connection1 = (XAConnection)cf1.createConnection(); + connection1.start(); + XASession session = connection1.createXASession(); + XAResource resource = session.getXAResource(); + Destination dest = new ActiveMQQueue(getName()); + + // publish a message + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + MessageProducer producer = session.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setText(getName()); + producer.send(message); + session.close(); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + + + session = connection1.createXASession(); + MessageConsumer consumer = session.createConsumer(dest); + tid = createXid(); + resource = session.getXAResource(); + resource.start(tid, XAResource.TMNOFLAGS); + TextMessage receivedMessage = (TextMessage) consumer.receive(1000); + session.close(); + assertNotNull(receivedMessage); + assertEquals(getName(), receivedMessage.getText()); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + + session = connection1.createXASession(); + consumer = session.createConsumer(dest); + tid = createXid(); + resource = session.getXAResource(); + resource.start(tid, XAResource.TMNOFLAGS); + assertNull(consumer.receive(1000)); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + } + + + public void testReadonlyNoLeak() throws Exception { + final String brokerName = "readOnlyNoLeak"; + BrokerService broker = BrokerFactory.createBroker(new URI("broker:(tcp://localhost:0)/" + brokerName)); + broker.setPersistent(false); + broker.start(); + ActiveMQXAConnectionFactory cf1 = new ActiveMQXAConnectionFactory("failover:(" + broker.getTransportConnectors().get(0).getConnectUri() + ")"); + cf1.setStatsEnabled(true); + ActiveMQXAConnection xaConnection = (ActiveMQXAConnection)cf1.createConnection(); + xaConnection.start(); + XASession session = xaConnection.createXASession(); + XAResource resource = session.getXAResource(); + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + session.close(); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + + assertTransactionGoneFromBroker(tid); + assertTransactionGoneFromConnection(brokerName, xaConnection.getClientID(), xaConnection.getConnectionInfo().getConnectionId(), tid); + assertSessionGone(xaConnection, session); + assertTransactionGoneFromFailoverState(xaConnection, tid); + + // two phase + session = xaConnection.createXASession(); + resource = session.getXAResource(); + tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + session.close(); + resource.end(tid, XAResource.TMSUCCESS); + assertEquals(XAResource.XA_RDONLY, resource.prepare(tid)); + + // no need for a commit on read only + assertTransactionGoneFromBroker(tid); + assertTransactionGoneFromConnection(brokerName, xaConnection.getClientID(), xaConnection.getConnectionInfo().getConnectionId(), tid); + assertSessionGone(xaConnection, session); + assertTransactionGoneFromFailoverState(xaConnection, tid); + + xaConnection.close(); + broker.stop(); + + } + + public void testCloseSendConnection() throws Exception { + String brokerName = "closeSend"; + BrokerService broker = BrokerFactory.createBroker(new URI("broker:(tcp://localhost:0)/" + brokerName)); + broker.start(); + broker.waitUntilStarted(); + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri()); + XAConnection connection = (XAConnection)cf.createConnection(); + connection.start(); + XASession session = connection.createXASession(); + XAResource resource = session.getXAResource(); + Destination dest = new ActiveMQQueue(getName()); + + // publish a message + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + MessageProducer producer = session.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setText(getName()); + producer.send(message); + + connection.close(); + + assertTransactionGoneFromBroker(tid); + + broker.stop(); + } + + public void testExceptionAfterClose() throws Exception { + + ActiveMQXAConnectionFactory cf1 = new ActiveMQXAConnectionFactory("vm://localhost?broker.persistent=false"); + XAConnection connection1 = (XAConnection)cf1.createConnection(); + connection1.start(); + + XASession session = connection1.createXASession(); + session.close(); + try { + session.commit(); + fail("expect exception after close"); + } catch (javax.jms.IllegalStateException expected) {} + + try { + session.rollback(); + fail("expect exception after close"); + } catch (javax.jms.IllegalStateException expected) {} + + try { + session.getTransacted(); + fail("expect exception after close"); + } catch (javax.jms.IllegalStateException expected) {} + } + + public void testRollbackXaErrorCode() throws Exception { + String brokerName = "rollbackErrorCode"; + BrokerService broker = BrokerFactory.createBroker(new URI("broker:(tcp://localhost:0)/" + brokerName)); + broker.start(); + broker.waitUntilStarted(); + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri()); + XAConnection connection = (XAConnection)cf.createConnection(); + connection.start(); + XASession session = connection.createXASession(); + XAResource resource = session.getXAResource(); + + Xid tid = createXid(); + try { + resource.rollback(tid); + fail("Expected xa exception on no tx"); + } catch (XAException expected) { + LOG.info("got expected xa", expected); + assertEquals("no tx", XAException.XAER_NOTA, expected.errorCode); + } + connection.close(); + broker.stop(); + } + + private void assertTransactionGoneFromFailoverState( + ActiveMQXAConnection connection1, Xid tid) throws Exception { + + FailoverTransport transport = (FailoverTransport) connection1.getTransport().narrow(FailoverTransport.class); + TransactionInfo info = new TransactionInfo(connection1.getConnectionInfo().getConnectionId(), new XATransactionId(tid), TransactionInfo.COMMIT_ONE_PHASE); + assertNull("transaction should not exist in the state tracker", + transport.getStateTracker().processCommitTransactionOnePhase(info)); + } + + private void assertSessionGone(ActiveMQXAConnection connection1, + XASession session) { + JMSConnectionStatsImpl stats = (JMSConnectionStatsImpl)connection1.getStats(); + // should be no dangling sessions maintained by the transaction + assertEquals("should be no sessions", 0, stats.getSessions().length); + } + + private void assertTransactionGoneFromConnection(String brokerName, String clientId, ConnectionId connectionId, Xid tid) throws Exception { + BrokerService broker = BrokerRegistry.getInstance().lookup(brokerName); + CopyOnWriteArrayList connections = broker.getTransportConnectors().get(0).getConnections(); + for (TransportConnection connection: connections) { + if (connection.getConnectionId().equals(clientId)) { + try { + connection.processPrepareTransaction(new TransactionInfo(connectionId, new XATransactionId(tid), TransactionInfo.PREPARE)); + fail("did not get expected excepton on missing transaction, it must be still there in error!"); + } catch (IllegalStateException expectedOnNoTransaction) { + } + } + } + } + + private void assertTransactionGoneFromBroker(Xid tid) throws Exception { + BrokerService broker = BrokerRegistry.getInstance().lookup("localhost"); + TransactionBroker transactionBroker = (TransactionBroker)broker.getBroker().getAdaptor(TransactionBroker.class); + try { + transactionBroker.getTransaction(null, new XATransactionId(tid), false); + fail("expected exception on tx not found"); + } catch (XAException expectedOnNotFound) { + } + } + + protected void assertCreateConnection(String uri) throws Exception { + // Start up a broker with a tcp connector. + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + TransportConnector connector = broker.addConnector(uri); + broker.start(); + + URI temp = new URI(uri); + // URI connectURI = connector.getServer().getConnectURI(); + // TODO this sometimes fails when using the actual local host name + URI currentURI = new URI(connector.getPublishableConnectString()); + + // sometimes the actual host name doesn't work in this test case + // e.g. on OS X so lets use the original details but just use the actual + // port + URI connectURI = new URI(temp.getScheme(), temp.getUserInfo(), temp.getHost(), currentURI.getPort(), + temp.getPath(), temp.getQuery(), temp.getFragment()); + + LOG.info("connection URI is: " + connectURI); + + // This should create the connection. + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory(connectURI); + Connection connection = cf.createConnection(); + + assertXAConnection(connection); + + assertNotNull(connection); + connection.close(); + + connection = cf.createXAConnection(); + + assertXAConnection(connection); + + assertNotNull(connection); + } + + private void assertXAConnection(Connection connection) { + assertTrue("Should be an XAConnection", connection instanceof XAConnection); + assertTrue("Should be an XATopicConnection", connection instanceof XATopicConnection); + assertTrue("Should be an XAQueueConnection", connection instanceof XAQueueConnection); + } + + public Xid createXid() throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + os.writeLong(++txGenerator); + os.close(); + final byte[] bs = baos.toByteArray(); + + return new Xid() { + public int getFormatId() { + return 86; + } + + public byte[] getGlobalTransactionId() { + return bs; + } + + public byte[] getBranchQualifier() { + return bs; + } + }; + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ClientTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ClientTestSupport.java new file mode 100644 index 0000000000..eafe359540 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ClientTestSupport.java @@ -0,0 +1,177 @@ +/** + * 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; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.JMSException; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatch; +import org.apache.activemq.command.RemoveInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.transport.TransportFactory; + +public class ClientTestSupport extends TestCase { + + protected BrokerService broker; + protected long idGenerator; + + private ActiveMQConnectionFactory connFactory; + private final String brokerURL = "vm://localhost?broker.persistent=false"; + + @Override + public void setUp() throws Exception { + final AtomicBoolean connected = new AtomicBoolean(false); + TransportConnector connector; + + // Start up a broker with a tcp connector. + try { + broker = BrokerFactory.createBroker(new URI(this.brokerURL)); + broker.getBrokerName(); + connector = new TransportConnector(TransportFactory.bind(new URI(this.brokerURL))) { + // Hook into the connector so we can assert that the server + // accepted a connection. + @Override + protected org.apache.activemq.broker.Connection createConnection(org.apache.activemq.transport.Transport transport) throws IOException { + connected.set(true); + return super.createConnection(transport); + } + }; + broker.addConnector(connector); + broker.start(); + + } catch (IOException e) { + throw new JMSException("Error creating broker " + e); + } catch (URISyntaxException e) { + throw new JMSException("Error creating broker " + e); + } + + URI connectURI; + connectURI = connector.getServer().getConnectURI(); + + // This should create the connection. + connFactory = new ActiveMQConnectionFactory(connectURI); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + public ActiveMQConnectionFactory getConnectionFactory() throws JMSException { + if (this.connFactory == null) { + throw new JMSException("ActiveMQConnectionFactory is null "); + } + return this.connFactory; + } + + // Helper Classes + protected ConnectionInfo createConnectionInfo() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + info.setConnectionId(new ConnectionId("connection:" + (++idGenerator))); + info.setClientId(info.getConnectionId().getValue()); + return info; + } + + protected SessionInfo createSessionInfo(ConnectionInfo connectionInfo) throws Exception { + SessionInfo info = new SessionInfo(connectionInfo, ++idGenerator); + return info; + } + + protected ConsumerInfo createConsumerInfo(SessionInfo sessionInfo, ActiveMQDestination destination) throws Exception { + ConsumerInfo info = new ConsumerInfo(sessionInfo, ++idGenerator); + info.setBrowser(false); + info.setDestination(destination); + info.setPrefetchSize(1000); + info.setDispatchAsync(false); + return info; + } + + protected RemoveInfo closeConsumerInfo(ConsumerInfo consumerInfo) { + return consumerInfo.createRemoveCommand(); + } + + protected MessageAck createAck(ConsumerInfo consumerInfo, Message msg, int count, byte ackType) { + MessageAck ack = new MessageAck(); + ack.setAckType(ackType); + ack.setConsumerId(consumerInfo.getConsumerId()); + ack.setDestination(msg.getDestination()); + ack.setLastMessageId(msg.getMessageId()); + ack.setMessageCount(count); + return ack; + } + + protected Message receiveMessage(StubConnection connection, int maxWait) throws InterruptedException { + while (true) { + Object o = connection.getDispatchQueue().poll(maxWait, TimeUnit.MILLISECONDS); + + if (o == null) { + return null; + } + + if (o instanceof MessageDispatch) { + MessageDispatch dispatch = (MessageDispatch)o; + return dispatch.getMessage(); + } + } + } + + protected Broker getBroker() throws Exception { + return this.broker != null ? this.broker.getBroker() : null; + } + + public static void removeMessageStore() { + if (System.getProperty("activemq.store.dir") != null) { + recursiveDelete(new File(System.getProperty("activemq.store.dir"))); + } + if (System.getProperty("derby.system.home") != null) { + recursiveDelete(new File(System.getProperty("derby.system.home"))); + } + } + + public static void recursiveDelete(File f) { + if (f.isDirectory()) { + File[] files = f.listFiles(); + for (int i = 0; i < files.length; i++) { + recursiveDelete(files[i]); + } + } + f.delete(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/CombinationTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/CombinationTestSupport.java new file mode 100644 index 0000000000..a11505c610 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/CombinationTestSupport.java @@ -0,0 +1,272 @@ +/** + * 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; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Poor mans way of getting JUnit to run a test case through a few different + * combinations of options. Usage: If you have a test case called testFoo what + * you want to run through a few combinations, of of values for the attributes + * age and color, you would something like: + * public void initCombosForTestFoo() { + * addCombinationValues( "age", new Object[]{ new Integer(21), new Integer(30) } ); + * addCombinationValues( "color", new Object[]{"blue", "green"} ); + * } + * + * The testFoo test case would be run for each possible combination of age and + * color that you setup in the initCombosForTestFoo method. Before each + * combination is run, the age and color fields of the test class are set to one + * of the values defined. This is done before the normal setUp method is called. + * If you want the test combinations to show up as separate test runs in the + * JUnit reports, add a suite method to your test case similar to: + * public static Test suite() { + * return suite(FooTest.class); + * } + * + * + * + */ +public abstract class CombinationTestSupport extends AutoFailTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(CombinationTestSupport.class); + + private final HashMap comboOptions = new HashMap(); + private boolean combosEvaluated; + private Map options; + protected File basedir; + + static protected File basedir(Class clazz) { + try { + ProtectionDomain protectionDomain = clazz.getProtectionDomain(); + return new File(new File(protectionDomain.getCodeSource().getLocation().getPath()), "../..").getCanonicalFile(); + } catch (IOException e) { + return new File("."); + } + } + + static class ComboOption { + final String attribute; + final LinkedHashSet values = new LinkedHashSet(); + + public ComboOption(String attribute, Collection options) { + this.attribute = attribute; + this.values.addAll(options); + } + } + + public CombinationTestSupport() { + basedir = basedir(getClass()); + } + public void addCombinationValues(String attribute, Object[] options) { + ComboOption co = this.comboOptions.get(attribute); + if (co == null) { + this.comboOptions.put(attribute, new ComboOption(attribute, Arrays.asList(options))); + } else { + co.values.addAll(Arrays.asList(options)); + } + } + + @Override + public void runBare() throws Throwable { + if (combosEvaluated) { + super.runBare(); + } else { + CombinationTestSupport[] combinations = getCombinations(); + for (int i = 0; i < combinations.length; i++) { + CombinationTestSupport test = combinations[i]; + if (getName() == null || getName().equals(test.getName())) { + test.runBare(); + } + } + } + } + + private void setOptions(Map options) throws NoSuchFieldException, IllegalAccessException { + this.options = options; + for (Iterator iterator = options.keySet().iterator(); iterator.hasNext();) { + String attribute = iterator.next(); + Object value = options.get(attribute); + try { + Field field = getClass().getField(attribute); + field.set(this, value); + } catch (Throwable e) { + try { + boolean found = false; + String setterName = "set" + attribute.substring(0, 1).toUpperCase() + + attribute.substring(1); + for(Method method : getClass().getMethods()) { + if (method.getName().equals(setterName)) { + method.invoke(this, value); + found = true; + break; + } + } + + if (!found) { + throw new NoSuchMethodError("No setter found for field: " + attribute); + } + + } catch(Throwable ex) { + LOG.info("Could not set field '" + attribute + "' to value '" + value + + "', make sure the field exists and is public or has a setter."); + } + } + } + } + + private CombinationTestSupport[] getCombinations() { + try { + Method method = getClass().getMethod("initCombos", (Class[])null); + method.invoke(this, (Object[])null); + } catch (Throwable e) { + } + + String name = getName().split(" ")[0]; + String comboSetupMethodName = "initCombosFor" + Character.toUpperCase(name.charAt(0)) + name.substring(1); + try { + Method method = getClass().getMethod(comboSetupMethodName, (Class[])null); + method.invoke(this, (Object[])null); + } catch (Throwable e) { + } + + try { + ArrayList> expandedOptions = new ArrayList>(); + expandCombinations(new ArrayList(comboOptions.values()), expandedOptions); + + if (expandedOptions.isEmpty()) { + combosEvaluated = true; + return new CombinationTestSupport[] {this}; + } else { + + ArrayList result = new ArrayList(); + // Run the test case for each possible combination + for (Iterator> iter = expandedOptions.iterator(); iter.hasNext();) { + CombinationTestSupport combo = (CombinationTestSupport)TestSuite.createTest(getClass(), name); + combo.combosEvaluated = true; + combo.setOptions(iter.next()); + result.add(combo); + } + + CombinationTestSupport rc[] = new CombinationTestSupport[result.size()]; + result.toArray(rc); + return rc; + } + } catch (Throwable e) { + combosEvaluated = true; + return new CombinationTestSupport[] {this}; + } + + } + + private void expandCombinations(List optionsLeft, List> expandedCombos) { + if (!optionsLeft.isEmpty()) { + HashMap map; + if (comboOptions.size() == optionsLeft.size()) { + map = new HashMap(); + expandedCombos.add(map); + } else { + map = expandedCombos.get(expandedCombos.size() - 1); + } + + LinkedList l = new LinkedList(optionsLeft); + ComboOption comboOption = l.removeLast(); + int i = 0; + if (comboOption.values.isEmpty() && !l.isEmpty()) { + expandCombinations(l, expandedCombos); + } else { + for (Iterator iter = comboOption.values.iterator(); iter.hasNext();) { + Object value = iter.next(); + if (i != 0) { + map = new HashMap(map); + expandedCombos.add(map); + } + map.put(comboOption.attribute, value); + expandCombinations(l, expandedCombos); + i++; + } + } + } + } + + public static Test suite(Class clazz) { + TestSuite suite = new TestSuite(); + + ArrayList names = new ArrayList(); + Method[] methods = clazz.getMethods(); + for (int i = 0; i < methods.length; i++) { + String name = methods[i].getName(); + if (names.contains(name) || !isPublicTestMethod(methods[i])) { + continue; + } + names.add(name); + Test test = TestSuite.createTest(clazz, name); + if (test instanceof CombinationTestSupport) { + CombinationTestSupport[] combinations = ((CombinationTestSupport)test).getCombinations(); + for (int j = 0; j < combinations.length; j++) { + suite.addTest(combinations[j]); + } + } else { + suite.addTest(test); + } + } + return suite; + } + + private static boolean isPublicTestMethod(Method m) { + return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); + } + + private static boolean isTestMethod(Method m) { + String name = m.getName(); + Class[] parameters = m.getParameterTypes(); + Class returnType = m.getReturnType(); + return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE); + } + + @Override + public String getName() { + return getName(false); + } + + public String getName(boolean original) { + if (options != null && !original) { + return super.getName() + " " + options; + } + return super.getName(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCleanupTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCleanupTest.java new file mode 100644 index 0000000000..f7a64acdc8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCleanupTest.java @@ -0,0 +1,69 @@ +/** + * 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; + +import javax.jms.JMSException; +import javax.jms.Session; + +import junit.framework.TestCase; + +/** + * + */ +public class ConnectionCleanupTest extends TestCase { + + private ActiveMQConnection connection; + + protected void setUp() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + connection = (ActiveMQConnection)factory.createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + connection.close(); + } + + /** + * @throws JMSException + */ + public void testChangeClientID() throws JMSException { + + connection.setClientID("test"); + connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + try { + connection.setClientID("test"); + // fail("Should have received JMSException"); + } catch (JMSException e) { + } + + connection.cleanup(); + connection.setClientID("test"); + + connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + try { + connection.setClientID("test"); + // fail("Should have received JMSException"); + } catch (JMSException e) { + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCloseMultipleTimesConcurrentTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCloseMultipleTimesConcurrentTest.java new file mode 100644 index 0000000000..ae15671ada --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCloseMultipleTimesConcurrentTest.java @@ -0,0 +1,96 @@ +/** + * 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; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import javax.jms.JMSException; +import javax.jms.Session; + +import junit.framework.TestCase; + +/** + * + */ +public class ConnectionCloseMultipleTimesConcurrentTest extends TestCase { + + private ActiveMQConnection connection; + private ExecutorService executor; + private int size = 200; + + protected void setUp() throws Exception { + executor = Executors.newFixedThreadPool(20); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + connection = (ActiveMQConnection)factory.createConnection(); + connection.start(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection.isStarted()) { + connection.stop(); + } + if (executor != null) { + executor.shutdownNow(); + } + } + + /** + * @throws javax.jms.JMSException + */ + public void testCloseMultipleTimes() throws Exception { + connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + assertTrue(connection.isStarted()); + assertFalse(connection.isClosed()); + + final CountDownLatch latch = new CountDownLatch(size); + + for (int i = 0; i < size; i++) { + executor.submit(new Runnable() { + @Override + public void run() { + try { + connection.close(); + + assertFalse(connection.isStarted()); + assertTrue(connection.isClosed()); + + latch.countDown(); + } catch (JMSException e) { + // ignore + } + } + }); + } + + boolean zero = latch.await(20, TimeUnit.SECONDS); + assertTrue("Should complete all", zero); + + // should not fail calling again + connection.close(); + + assertFalse(connection.isStarted()); + assertTrue(connection.isClosed()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCloseMultipleTimesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCloseMultipleTimesTest.java new file mode 100644 index 0000000000..3e78d73a02 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConnectionCloseMultipleTimesTest.java @@ -0,0 +1,67 @@ +/** + * 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; + +import javax.jms.JMSException; +import javax.jms.Session; + +import junit.framework.TestCase; + +/** + * + */ +public class ConnectionCloseMultipleTimesTest extends TestCase { + + private ActiveMQConnection connection; + + protected void setUp() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + connection = (ActiveMQConnection)factory.createConnection(); + connection.start(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection.isStarted()) { + connection.stop(); + } + } + + /** + * @throws javax.jms.JMSException + */ + public void testCloseMultipleTimes() throws JMSException { + connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + assertTrue(connection.isStarted()); + assertFalse(connection.isClosed()); + + connection.close(); + + assertFalse(connection.isStarted()); + assertTrue(connection.isClosed()); + + // should not fail calling again + connection.close(); + + assertFalse(connection.isStarted()); + assertTrue(connection.isClosed()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConsumerReceiveWithTimeoutTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConsumerReceiveWithTimeoutTest.java new file mode 100644 index 0000000000..b34fe7f739 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ConsumerReceiveWithTimeoutTest.java @@ -0,0 +1,87 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +/** + * + */ +public class ConsumerReceiveWithTimeoutTest extends TestSupport { + + private Connection connection; + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + /** + * Test to check if consumer thread wakes up inside a receive(timeout) after + * a message is dispatched to the consumer + * + * @throws javax.jms.JMSException + */ + public void testConsumerReceiveBeforeMessageDispatched() throws JMSException { + + connection.start(); + + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue queue = session.createQueue("test"); + + Thread t = new Thread() { + public void run() { + try { + // wait for 10 seconds to allow consumer.receive to be run + // first + Thread.sleep(10000); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + t.start(); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(60000); + assertNotNull(msg); + session.close(); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/CreateConsumerButDontStartConnectionWarningTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/CreateConsumerButDontStartConnectionWarningTest.java new file mode 100644 index 0000000000..773e87129f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/CreateConsumerButDontStartConnectionWarningTest.java @@ -0,0 +1,43 @@ +/** + * 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; + +import javax.jms.JMSException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class CreateConsumerButDontStartConnectionWarningTest extends JmsQueueSendReceiveTest { + private static final transient Logger LOG = LoggerFactory.getLogger(CreateConsumerButDontStartConnectionWarningTest.class); + + @Override + protected void startConnection() throws JMSException { + // don't start the connection + } + + @Override + protected void assertMessagesAreReceived() throws JMSException { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + LOG.warn("Caught: " + e, e); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/EmbeddedBrokerAndConnectionTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/EmbeddedBrokerAndConnectionTestSupport.java new file mode 100644 index 0000000000..aa39cc1085 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/EmbeddedBrokerAndConnectionTestSupport.java @@ -0,0 +1,44 @@ +/** + * 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; + +import javax.jms.Connection; + +/** + * A base class for a test case which creates an embedded broker and uses a connection and session + * + * + */ +public abstract class EmbeddedBrokerAndConnectionTestSupport extends EmbeddedBrokerTestSupport { + protected Connection connection; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + connection = createConnection(); + connection.start(); + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/EmbeddedBrokerTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/EmbeddedBrokerTestSupport.java new file mode 100644 index 0000000000..b049e960c9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/EmbeddedBrokerTestSupport.java @@ -0,0 +1,143 @@ +/** + * 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; + +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.springframework.jms.core.JmsTemplate; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; + +/** + * A useful base class which creates and closes an embedded broker + * + * + */ +public abstract class EmbeddedBrokerTestSupport extends CombinationTestSupport { + + protected BrokerService broker; + // protected String bindAddress = "tcp://localhost:61616"; + protected String bindAddress = "vm://localhost"; + protected ConnectionFactory connectionFactory; + protected boolean useTopic; + protected ActiveMQDestination destination; + protected JmsTemplate template; + + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + startBroker(); + + connectionFactory = createConnectionFactory(); + + destination = createDestination(); + + template = createJmsTemplate(); + template.setDefaultDestination(destination); + template.setPubSubDomain(useTopic); + template.afterPropertiesSet(); + } + + protected void tearDown() throws Exception { + if (broker != null) { + try { + broker.stop(); + } catch (Exception e) { + } + } + } + + /** + * Factory method to create a new {@link JmsTemplate} + * + * @return a newly created JmsTemplate + */ + protected JmsTemplate createJmsTemplate() { + return new JmsTemplate(connectionFactory); + } + + /** + * Factory method to create a new {@link Destination} + * + * @return newly created Destinaiton + */ + protected ActiveMQDestination createDestination() { + return createDestination(getDestinationString()); + } + + /** + * Factory method to create the destination in either the queue or topic + * space based on the value of the {@link #useTopic} field + */ + protected ActiveMQDestination createDestination(String subject) { + if (useTopic) { + return new ActiveMQTopic(subject); + } else { + return new ActiveMQQueue(subject); + } + } + + /** + * Returns the name of the destination used in this test case + */ + protected String getDestinationString() { + return getClass().getName() + "." + getName(); + } + + /** + * Factory method to create a new {@link ConnectionFactory} instance + * + * @return a newly created connection factory + */ + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(bindAddress); + } + + /** + * Factory method to create a new broker + * + * @throws Exception + */ + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(isPersistent()); + answer.addConnector(bindAddress); + return answer; + } + + protected void startBroker() throws Exception { + broker.start(); + } + + /** + * @return whether or not persistence should be used + */ + protected boolean isPersistent() { + return false; + } + + /** + * Factory method to create a new connection + */ + protected Connection createConnection() throws Exception { + return connectionFactory.createConnection(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExclusiveConsumerStartupDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExclusiveConsumerStartupDestinationTest.java new file mode 100644 index 0000000000..7aa22e36a2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExclusiveConsumerStartupDestinationTest.java @@ -0,0 +1,203 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; + +public class ExclusiveConsumerStartupDestinationTest extends EmbeddedBrokerTestSupport{ + + private static final String VM_BROKER_URL = "vm://localhost"; + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + PolicyMap map = new PolicyMap(); + PolicyEntry entry = new PolicyEntry(); + entry.setAllConsumersExclusiveByDefault(true); + map.setDefaultEntry(entry); + answer.setDestinationPolicy(map); + return answer; + } + + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/exclusive-consumer-startup-destination.xml"; + } + + private Connection createConnection(final boolean start) throws JMSException { + ConnectionFactory cf = new ActiveMQConnectionFactory(VM_BROKER_URL); + Connection conn = cf.createConnection(); + if (start) { + conn.start(); + } + return conn; + } + + public void testExclusiveConsumerSelectedCreatedFirst() throws JMSException, InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE1"); + MessageConsumer exclusiveConsumer = exclusiveSession.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE1"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE1"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + // TODO need two send a 2nd message - bug AMQ-1024 + // producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer.receive(100)); + assertNull(fallbackConsumer.receive(100)); + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + } + + public void testFailoverToAnotherExclusiveConsumerCreatedFirst() throws JMSException, + InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession1 = null; + Session exclusiveSession2 = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + exclusiveSession2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // This creates the exclusive consumer first which avoids AMQ-1024 + // bug. + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE2"); + MessageConsumer exclusiveConsumer1 = exclusiveSession1.createConsumer(exclusiveQueue); + MessageConsumer exclusiveConsumer2 = exclusiveSession2.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE2"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE2"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer1.receive(100)); + assertNull(exclusiveConsumer2.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + // Close the exclusive consumer to verify the non-exclusive consumer + // takes over + exclusiveConsumer1.close(); + + producer.send(msg); + producer.send(msg); + + assertNotNull("Should have received a message", exclusiveConsumer2.receive(100)); + assertNull("Should not have received a message", fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + + } + + public void testFailoverToNonExclusiveConsumer() throws JMSException, InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // This creates the exclusive consumer first which avoids AMQ-1024 + // bug. + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE3"); + MessageConsumer exclusiveConsumer = exclusiveSession.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE3"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE3"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + // Close the exclusive consumer to verify the non-exclusive consumer + // takes over + exclusiveConsumer.close(); + + producer.send(msg); + + assertNotNull(fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExclusiveConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExclusiveConsumerTest.java new file mode 100644 index 0000000000..53ef28fc5a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExclusiveConsumerTest.java @@ -0,0 +1,357 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQQueue; + +public class ExclusiveConsumerTest extends TestCase { + + private static final String VM_BROKER_URL = "vm://localhost?broker.persistent=false&broker.useJmx=true"; + + public ExclusiveConsumerTest(String name) { + super(name); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + private Connection createConnection(final boolean start) throws JMSException { + ConnectionFactory cf = new ActiveMQConnectionFactory(VM_BROKER_URL); + Connection conn = cf.createConnection(); + if (start) { + conn.start(); + } + return conn; + } + + public void testExclusiveConsumerSelectedCreatedFirst() throws JMSException, InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE1?consumer.exclusive=true"); + MessageConsumer exclusiveConsumer = exclusiveSession.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE1"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE1"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + // TODO need two send a 2nd message - bug AMQ-1024 + // producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + + } + + public void testExclusiveConsumerSelectedCreatedAfter() throws JMSException, InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE5"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE5?consumer.exclusive=true"); + MessageConsumer exclusiveConsumer = exclusiveSession.createConsumer(exclusiveQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE5"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + + } + + public void testFailoverToAnotherExclusiveConsumerCreatedFirst() throws JMSException, + InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession1 = null; + Session exclusiveSession2 = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + exclusiveSession2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // This creates the exclusive consumer first which avoids AMQ-1024 + // bug. + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE2?consumer.exclusive=true"); + MessageConsumer exclusiveConsumer1 = exclusiveSession1.createConsumer(exclusiveQueue); + MessageConsumer exclusiveConsumer2 = exclusiveSession2.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE2"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE2"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer1.receive(100)); + assertNull(exclusiveConsumer2.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + // Close the exclusive consumer to verify the non-exclusive consumer + // takes over + exclusiveConsumer1.close(); + + producer.send(msg); + producer.send(msg); + + assertNotNull(exclusiveConsumer2.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + + } + + public void testFailoverToAnotherExclusiveConsumerCreatedAfter() throws JMSException, + InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession1 = null; + Session exclusiveSession2 = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + exclusiveSession2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // This creates the exclusive consumer first which avoids AMQ-1024 + // bug. + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE6?consumer.exclusive=true"); + MessageConsumer exclusiveConsumer1 = exclusiveSession1.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE6"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + MessageConsumer exclusiveConsumer2 = exclusiveSession2.createConsumer(exclusiveQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE6"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer1.receive(100)); + assertNull(exclusiveConsumer2.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + // Close the exclusive consumer to verify the non-exclusive consumer + // takes over + exclusiveConsumer1.close(); + + producer.send(msg); + producer.send(msg); + + assertNotNull(exclusiveConsumer2.receive(1000)); + assertNull(fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + + } + + public void testFailoverToNonExclusiveConsumer() throws JMSException, InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // This creates the exclusive consumer first which avoids AMQ-1024 + // bug. + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE3?consumer.exclusive=true"); + MessageConsumer exclusiveConsumer = exclusiveSession.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE3"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE3"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + // Close the exclusive consumer to verify the non-exclusive consumer + // takes over + exclusiveConsumer.close(); + + producer.send(msg); + + assertNotNull(fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + + } + + public void testFallbackToExclusiveConsumer() throws JMSException, InterruptedException { + Connection conn = createConnection(true); + + Session exclusiveSession = null; + Session fallbackSession = null; + Session senderSession = null; + + try { + + exclusiveSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + fallbackSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // This creates the exclusive consumer first which avoids AMQ-1024 + // bug. + ActiveMQQueue exclusiveQueue = new ActiveMQQueue("TEST.QUEUE4?consumer.exclusive=true"); + MessageConsumer exclusiveConsumer = exclusiveSession.createConsumer(exclusiveQueue); + + ActiveMQQueue fallbackQueue = new ActiveMQQueue("TEST.QUEUE4"); + MessageConsumer fallbackConsumer = fallbackSession.createConsumer(fallbackQueue); + + ActiveMQQueue senderQueue = new ActiveMQQueue("TEST.QUEUE4"); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + producer.send(msg); + Thread.sleep(100); + + // Verify exclusive consumer receives the message. + assertNotNull(exclusiveConsumer.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + // Close the exclusive consumer to verify the non-exclusive consumer + // takes over + exclusiveConsumer.close(); + + producer.send(msg); + + // Verify other non-exclusive consumer receices the message. + assertNotNull(fallbackConsumer.receive(100)); + + // Create exclusive consumer to determine if it will start receiving + // the messages. + exclusiveConsumer = exclusiveSession.createConsumer(exclusiveQueue); + + producer.send(msg); + assertNotNull(exclusiveConsumer.receive(100)); + assertNull(fallbackConsumer.receive(100)); + + } finally { + fallbackSession.close(); + senderSession.close(); + conn.close(); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExpiryHogTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExpiryHogTest.java new file mode 100644 index 0000000000..eff6efa802 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ExpiryHogTest.java @@ -0,0 +1,82 @@ +/** + * 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; + +import java.util.concurrent.TimeUnit; +import javax.jms.ConnectionFactory; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * User: gtully + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class ExpiryHogTest extends JmsMultipleClientsTestSupport { + boolean sleep = false; + + int numMessages = 4; + + @Test(timeout = 2 * 60 * 1000) + public void testImmediateDispatchWhenCacheDisabled() throws Exception { + ConnectionFactory f = createConnectionFactory(); + destination = createDestination(); + startConsumers(f, destination); + sleep = true; + this.startProducers(f, destination, numMessages); + allMessagesList.assertMessagesReceived(numMessages); + } + + protected BrokerService createBroker() throws Exception { + BrokerService bs = new BrokerService(); + bs.setDeleteAllMessagesOnStartup(true); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setExpireMessagesPeriod(5000); + defaultEntry.setUseCache(false); + policyMap.setDefaultEntry(defaultEntry); + bs.setDestinationPolicy(policyMap); + + KahaDBPersistenceAdapter ad = (KahaDBPersistenceAdapter) bs.getPersistenceAdapter(); + ad.setConcurrentStoreAndDispatchQueues(true); + return bs; + } + + protected TextMessage createTextMessage(Session session, String initText) throws Exception { + if (sleep) { + TimeUnit.SECONDS.sleep(10); + } + TextMessage msg = super.createTextMessage(session, initText); + msg.setJMSExpiration(4000); + return msg; + } + + @Override + @Before + public void setUp() throws Exception { + autoFail = false; + persistent = true; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSConsumerTest.java new file mode 100644 index 0000000000..c793dc8e2c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSConsumerTest.java @@ -0,0 +1,937 @@ +/** + * 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; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +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 javax.jms.BytesMessage; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.management.ObjectName; + +import junit.framework.Test; + +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test cases used to test the JMS message consumer. + * + * + */ +public class JMSConsumerTest extends JmsTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(JMSConsumerTest.class); + + public ActiveMQDestination destination; + public int deliveryMode; + public int prefetch; + public int ackMode; + public byte destinationType; + public boolean durableConsumer; + + public static Test suite() { + return suite(JMSConsumerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void initCombosForTestMessageListenerWithConsumerCanBeStopped() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testMessageListenerWithConsumerCanBeStopped() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch done1 = new CountDownLatch(1); + final CountDownLatch done2 = new CountDownLatch(1); + + // Receive a message with the JMS API + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer)session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + counter.incrementAndGet(); + if (counter.get() == 1) { + done1.countDown(); + } + if (counter.get() == 2) { + done2.countDown(); + } + } + }); + + // Send a first message to make sure that the consumer dispatcher is + // running + sendMessages(session, destination, 1); + assertTrue(done1.await(1, TimeUnit.SECONDS)); + assertEquals(1, counter.get()); + + // Stop the consumer. + consumer.stop(); + + // Send a message, but should not get delivered. + sendMessages(session, destination, 1); + assertFalse(done2.await(1, TimeUnit.SECONDS)); + assertEquals(1, counter.get()); + + // Start the consumer, and the message should now get delivered. + consumer.start(); + assertTrue(done2.await(1, TimeUnit.SECONDS)); + assertEquals(2, counter.get()); + } + + + public void testMessageListenerWithConsumerCanBeStoppedConcurently() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch closeDone = new CountDownLatch(1); + + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE); + + // preload the queue + sendMessages(session, destination, 2000); + + + final ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer)session.createConsumer(destination); + + final Map exceptions = + Collections.synchronizedMap(new HashMap()); + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error("Uncaught exception:", e); + exceptions.put(t, e); + } + }); + + final class AckAndClose implements Runnable { + private final Message message; + + public AckAndClose(Message m) { + this.message = m; + } + + @Override + public void run() { + try { + int count = counter.incrementAndGet(); + if (count == 590) { + // close in a separate thread is ok by jms + consumer.close(); + closeDone.countDown(); + } + if (count % 200 == 0) { + // ensure there are some outstanding messages + // ack every 200 + message.acknowledge(); + } + } catch (Exception e) { + LOG.error("Exception on close or ack:", e); + exceptions.put(Thread.currentThread(), e); + } + } + }; + + final ExecutorService executor = Executors.newCachedThreadPool(); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + // ack and close eventually in separate thread + executor.execute(new AckAndClose(m)); + } + }); + + assertTrue(closeDone.await(20, TimeUnit.SECONDS)); + // await possible exceptions + Thread.sleep(1000); + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + } + + + public void initCombosForTestMutiReceiveWithPrefetch1() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("ackMode", new Object[] {Integer.valueOf(Session.AUTO_ACKNOWLEDGE), Integer.valueOf(Session.DUPS_OK_ACKNOWLEDGE), + Integer.valueOf(Session.CLIENT_ACKNOWLEDGE)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testMutiReceiveWithPrefetch1() throws Exception { + + // Set prefetch to 1 + connection.getPrefetchPolicy().setAll(1); + connection.start(); + + // Use all the ack modes + Session session = connection.createSession(false, ackMode); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + sendMessages(session, destination, 4); + + // Make sure 4 messages were delivered. + Message message = null; + for (int i = 0; i < 4; i++) { + message = consumer.receive(1000); + assertNotNull(message); + } + assertNull(consumer.receiveNoWait()); + message.acknowledge(); + } + + public void initCombosForTestDurableConsumerSelectorChange() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testDurableConsumerSelectorChange() throws Exception { + + // Receive a message with the JMS API + connection.setClientID("test"); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + MessageConsumer consumer = session.createDurableSubscriber((Topic)destination, "test", "color='red'", false); + + // Send the messages + TextMessage message = session.createTextMessage("1st"); + message.setStringProperty("color", "red"); + producer.send(message); + + Message m = consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", ((TextMessage)m).getText()); + + // Change the subscription. + consumer.close(); + consumer = session.createDurableSubscriber((Topic)destination, "test", "color='blue'", false); + + message = session.createTextMessage("2nd"); + message.setStringProperty("color", "red"); + producer.send(message); + message = session.createTextMessage("3rd"); + message.setStringProperty("color", "blue"); + producer.send(message); + + // Selector should skip the 2nd message. + m = consumer.receive(1000); + assertNotNull(m); + assertEquals("3rd", ((TextMessage)m).getText()); + + assertNull(consumer.receiveNoWait()); + } + + public void initCombosForTestSendReceiveBytesMessage() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testSendReceiveBytesMessage() throws Exception { + + // Receive a message with the JMS API + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(destination); + + BytesMessage message = session.createBytesMessage(); + message.writeBoolean(true); + message.writeBoolean(false); + producer.send(message); + + // Make sure only 1 message was delivered. + BytesMessage m = (BytesMessage)consumer.receive(1000); + assertNotNull(m); + assertTrue(m.readBoolean()); + assertFalse(m.readBoolean()); + + assertNull(consumer.receiveNoWait()); + } + + public void initCombosForTestSetMessageListenerAfterStart() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testSetMessageListenerAfterStart() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch done = new CountDownLatch(1); + + // Receive a message with the JMS API + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + sendMessages(session, destination, 4); + + // See if the message get sent to the listener + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + counter.incrementAndGet(); + if (counter.get() == 4) { + done.countDown(); + } + } + }); + + assertTrue(done.await(1000, TimeUnit.MILLISECONDS)); + Thread.sleep(200); + + // Make sure only 4 messages were delivered. + assertEquals(4, counter.get()); + } + + public void initCombosForTestPassMessageListenerIntoCreateConsumer() { + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testPassMessageListenerIntoCreateConsumer() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch done = new CountDownLatch(1); + + // Receive a message with the JMS API + connection.start(); + ActiveMQSession session = (ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination, new MessageListener() { + @Override + public void onMessage(Message m) { + counter.incrementAndGet(); + if (counter.get() == 4) { + done.countDown(); + } + } + }); + assertNotNull(consumer); + + // Send the messages + sendMessages(session, destination, 4); + + assertTrue(done.await(1000, TimeUnit.MILLISECONDS)); + Thread.sleep(200); + + // Make sure only 4 messages were delivered. + assertEquals(4, counter.get()); + } + + public void initCombosForTestMessageListenerOnMessageCloseUnackedWithPrefetch1StayInQueue() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("ackMode", new Object[] {Integer.valueOf(Session.CLIENT_ACKNOWLEDGE)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE)}); + } + + public void testMessageListenerOnMessageCloseUnackedWithPrefetch1StayInQueue() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch sendDone = new CountDownLatch(1); + final CountDownLatch got2Done = new CountDownLatch(1); + + // Set prefetch to 1 + connection.getPrefetchPolicy().setAll(1); + // This test case does not work if optimized message dispatch is used as + // the main thread send block until the consumer receives the + // message. This test depends on thread decoupling so that the main + // thread can stop the consumer thread. + connection.setOptimizedMessageDispatch(false); + connection.start(); + + // Use all the ack modes + Session session = connection.createSession(false, ackMode); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + try { + TextMessage tm = (TextMessage)m; + LOG.info("Got in first listener: " + tm.getText()); + assertEquals("" + counter.get(), tm.getText()); + counter.incrementAndGet(); + if (counter.get() == 2) { + sendDone.await(); + connection.close(); + got2Done.countDown(); + } + tm.acknowledge(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); + + // Send the messages + sendMessages(session, destination, 4); + sendDone.countDown(); + + // Wait for first 2 messages to arrive. + assertTrue(got2Done.await(100000, TimeUnit.MILLISECONDS)); + + // Re-start connection. + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + + connection.getPrefetchPolicy().setAll(1); + connection.start(); + + // Pickup the remaining messages. + final CountDownLatch done2 = new CountDownLatch(1); + session = connection.createSession(false, ackMode); + consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + try { + TextMessage tm = (TextMessage)m; + LOG.info("Got in second listener: " + tm.getText()); + // order is not guaranteed as the connection is started before the listener is set. + // assertEquals("" + counter.get(), tm.getText()); + counter.incrementAndGet(); + if (counter.get() == 4) { + done2.countDown(); + } + } catch (Throwable e) { + LOG.error("unexpected ex onMessage: ", e); + } + } + }); + + assertTrue(done2.await(1000, TimeUnit.MILLISECONDS)); + Thread.sleep(200); + + // assert msg 2 was redelivered as close() from onMessages() will only ack in auto_ack and dups_ok mode + assertEquals(5, counter.get()); + } + + public void initCombosForTestMessageListenerAutoAckOnCloseWithPrefetch1() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("ackMode", new Object[] {Integer.valueOf(Session.AUTO_ACKNOWLEDGE), Integer.valueOf(Session.CLIENT_ACKNOWLEDGE)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE)}); + } + + public void testMessageListenerAutoAckOnCloseWithPrefetch1() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch sendDone = new CountDownLatch(1); + final CountDownLatch got2Done = new CountDownLatch(1); + + // Set prefetch to 1 + connection.getPrefetchPolicy().setAll(1); + // This test case does not work if optimized message dispatch is used as + // the main thread send block until the consumer receives the + // message. This test depends on thread decoupling so that the main + // thread can stop the consumer thread. + connection.setOptimizedMessageDispatch(false); + connection.start(); + + // Use all the ack modes + Session session = connection.createSession(false, ackMode); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + try { + TextMessage tm = (TextMessage)m; + LOG.info("Got in first listener: " + tm.getText()); + assertEquals("" + counter.get(), tm.getText()); + counter.incrementAndGet(); + m.acknowledge(); + if (counter.get() == 2) { + sendDone.await(); + connection.close(); + got2Done.countDown(); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); + + // Send the messages + sendMessages(session, destination, 4); + sendDone.countDown(); + + // Wait for first 2 messages to arrive. + assertTrue(got2Done.await(100000, TimeUnit.MILLISECONDS)); + + // Re-start connection. + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + + connection.getPrefetchPolicy().setAll(1); + connection.start(); + + // Pickup the remaining messages. + final CountDownLatch done2 = new CountDownLatch(1); + session = connection.createSession(false, ackMode); + consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + try { + TextMessage tm = (TextMessage)m; + LOG.info("Got in second listener: " + tm.getText()); + counter.incrementAndGet(); + if (counter.get() == 4) { + done2.countDown(); + } + } catch (Throwable e) { + LOG.error("unexpected ex onMessage: ", e); + } + } + }); + + assertTrue(done2.await(1000, TimeUnit.MILLISECONDS)); + Thread.sleep(200); + + // close from onMessage with Auto_ack will ack + // Make sure only 4 messages were delivered. + assertEquals(4, counter.get()); + } + + public void initCombosForTestMessageListenerWithConsumerWithPrefetch1() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testMessageListenerWithConsumerWithPrefetch1() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch done = new CountDownLatch(1); + + // Receive a message with the JMS API + connection.getPrefetchPolicy().setAll(1); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + counter.incrementAndGet(); + if (counter.get() == 4) { + done.countDown(); + } + } + }); + + // Send the messages + sendMessages(session, destination, 4); + + assertTrue(done.await(1000, TimeUnit.MILLISECONDS)); + Thread.sleep(200); + + // Make sure only 4 messages were delivered. + assertEquals(4, counter.get()); + } + + public void initCombosForTestMessageListenerWithConsumer() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testMessageListenerWithConsumer() throws Exception { + + final AtomicInteger counter = new AtomicInteger(0); + final CountDownLatch done = new CountDownLatch(1); + + // Receive a message with the JMS API + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message m) { + counter.incrementAndGet(); + if (counter.get() == 4) { + done.countDown(); + } + } + }); + + // Send the messages + sendMessages(session, destination, 4); + + assertTrue(done.await(1000, TimeUnit.MILLISECONDS)); + Thread.sleep(200); + + // Make sure only 4 messages were delivered. + assertEquals(4, counter.get()); + } + + public void initCombosForTestUnackedWithPrefetch1StayInQueue() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("ackMode", new Object[] {Integer.valueOf(Session.AUTO_ACKNOWLEDGE), Integer.valueOf(Session.DUPS_OK_ACKNOWLEDGE), + Integer.valueOf(Session.CLIENT_ACKNOWLEDGE)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE)}); + } + + public void testUnackedWithPrefetch1StayInQueue() throws Exception { + + // Set prefetch to 1 + connection.getPrefetchPolicy().setAll(1); + connection.start(); + + // Use all the ack modes + Session session = connection.createSession(false, ackMode); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + sendMessages(session, destination, 4); + + // Only pick up the first 2 messages. + Message message = null; + for (int i = 0; i < 2; i++) { + message = consumer.receive(1000); + assertNotNull(message); + } + message.acknowledge(); + + connection.close(); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.getPrefetchPolicy().setAll(1); + connection.start(); + + // Use all the ack modes + session = connection.createSession(false, ackMode); + consumer = session.createConsumer(destination); + + // Pickup the rest of the messages. + for (int i = 0; i < 2; i++) { + message = consumer.receive(1000); + assertNotNull(message); + } + message.acknowledge(); + assertNull(consumer.receiveNoWait()); + + } + + public void initCombosForTestPrefetch1MessageNotDispatched() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + } + + public void testPrefetch1MessageNotDispatched() throws Exception { + + // Set prefetch to 1 + connection.getPrefetchPolicy().setAll(1); + connection.start(); + + Session session = connection.createSession(true, 0); + destination = new ActiveMQQueue("TEST"); + MessageConsumer consumer = session.createConsumer(destination); + + // Send 2 messages to the destination. + sendMessages(session, destination, 2); + session.commit(); + + // The prefetch should fill up with 1 message. + // Since prefetch is still full, the 2nd message should get dispatched + // to another consumer.. lets create the 2nd consumer test that it does + // make sure it does. + ActiveMQConnection connection2 = (ActiveMQConnection)factory.createConnection(); + connection2.start(); + connections.add(connection2); + Session session2 = connection2.createSession(true, 0); + MessageConsumer consumer2 = session2.createConsumer(destination); + + // Pick up the first message. + Message message1 = consumer.receive(1000); + assertNotNull(message1); + + // Pick up the 2nd messages. + Message message2 = consumer2.receive(5000); + assertNotNull(message2); + + session.commit(); + session2.commit(); + + assertNull(consumer.receiveNoWait()); + + } + + public void initCombosForTestDontStart() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testDontStart() throws Exception { + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + sendMessages(session, destination, 1); + + // Make sure no messages were delivered. + assertNull(consumer.receive(1000)); + } + + public void initCombosForTestStartAfterSend() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testStartAfterSend() throws Exception { + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + sendMessages(session, destination, 1); + + // Start the conncection after the message was sent. + connection.start(); + + // Make sure only 1 message was delivered. + assertNotNull(consumer.receive(1000)); + assertNull(consumer.receiveNoWait()); + } + + public void initCombosForTestReceiveMessageWithConsumer() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testReceiveMessageWithConsumer() throws Exception { + + // Receive a message with the JMS API + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + sendMessages(session, destination, 1); + + // Make sure only 1 message was delivered. + Message m = consumer.receive(1000); + assertNotNull(m); + assertEquals("0", ((TextMessage)m).getText()); + assertNull(consumer.receiveNoWait()); + } + + + public void testDupsOkConsumer() throws Exception { + + // Receive a message with the JMS API + connection.start(); + Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE); + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + sendMessages(session, destination, 4); + + // Make sure only 4 message are delivered. + for( int i=0; i < 4; i++){ + Message m = consumer.receive(1000); + assertNotNull(m); + } + assertNull(consumer.receive(1000)); + + // Close out the consumer.. no other messages should be left on the queue. + consumer.close(); + + consumer = session.createConsumer(destination); + assertNull(consumer.receive(1000)); + } + + public void testRedispatchOfUncommittedTx() throws Exception { + + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE); + + sendMessages(connection, destination, 2); + + MessageConsumer consumer = session.createConsumer(destination); + assertNotNull(consumer.receive(1000)); + assertNotNull(consumer.receive(1000)); + + // install another consumer while message dispatch is unacked/uncommitted + Session redispatchSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer redispatchConsumer = redispatchSession.createConsumer(destination); + + // no commit so will auto rollback and get re-dispatched to redisptachConsumer + session.close(); + + Message msg = redispatchConsumer.receive(1000); + assertNotNull(msg); + assertTrue("redelivered flag set", msg.getJMSRedelivered()); + assertEquals(2, msg.getLongProperty("JMSXDeliveryCount")); + + msg = redispatchConsumer.receive(1000); + assertNotNull(msg); + assertTrue(msg.getJMSRedelivered()); + assertEquals(2, msg.getLongProperty("JMSXDeliveryCount")); + redispatchSession.commit(); + + assertNull(redispatchConsumer.receive(500)); + redispatchSession.close(); + } + + + public void testRedispatchOfRolledbackTx() throws Exception { + + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE); + + sendMessages(connection, destination, 2); + + MessageConsumer consumer = session.createConsumer(destination); + assertNotNull(consumer.receive(1000)); + assertNotNull(consumer.receive(1000)); + + // install another consumer while message dispatch is unacked/uncommitted + Session redispatchSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer redispatchConsumer = redispatchSession.createConsumer(destination); + + session.rollback(); + session.close(); + + Message msg = redispatchConsumer.receive(1000); + assertNotNull(msg); + assertTrue(msg.getJMSRedelivered()); + assertEquals(2, msg.getLongProperty("JMSXDeliveryCount")); + msg = redispatchConsumer.receive(1000); + assertNotNull(msg); + assertTrue(msg.getJMSRedelivered()); + assertEquals(2, msg.getLongProperty("JMSXDeliveryCount")); + redispatchSession.commit(); + + assertNull(redispatchConsumer.receive(500)); + redispatchSession.close(); + } + + + public void initCombosForTestAckOfExpired() { + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testAckOfExpired() throws Exception { + + ActiveMQConnectionFactory fact = new ActiveMQConnectionFactory("vm://localhost?jms.prefetchPolicy.all=4&jms.sendAcksAsync=false"); + connection = fact.createActiveMQConnection(); + + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = (ActiveMQDestination) (destinationType == ActiveMQDestination.QUEUE_TYPE ? + session.createQueue("test") : session.createTopic("test")); + + MessageConsumer consumer = session.createConsumer(destination); + connection.setStatsEnabled(true); + + Session sendSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = sendSession.createProducer(destination); + producer.setTimeToLive(1000); + final int count = 4; + for (int i = 0; i < count; i++) { + TextMessage message = sendSession.createTextMessage("" + i); + producer.send(message); + } + + // let first bunch in queue expire + Thread.sleep(2000); + + producer.setTimeToLive(0); + for (int i = 0; i < count; i++) { + TextMessage message = sendSession.createTextMessage("no expiry" + i); + producer.send(message); + } + + ActiveMQMessageConsumer amqConsumer = (ActiveMQMessageConsumer) consumer; + + for(int i=0; i props = new HashMap(); + + @Override + public String getJMSMessageID() throws JMSException { + return messageId; + } + + @Override + public void setJMSMessageID(String arg0) throws JMSException { + messageId = arg0; + } + + @Override + public long getJMSTimestamp() throws JMSException { + return timestamp; + } + + @Override + public void setJMSTimestamp(long arg0) throws JMSException { + timestamp = arg0; + } + + @Override + public byte[] getJMSCorrelationIDAsBytes() throws JMSException { + return null; + } + + @Override + public void setJMSCorrelationIDAsBytes(byte[] arg0) throws JMSException { + } + + @Override + public void setJMSCorrelationID(String arg0) throws JMSException { + correlationId = arg0; + } + + @Override + public String getJMSCorrelationID() throws JMSException { + return correlationId; + } + + @Override + public Destination getJMSReplyTo() throws JMSException { + return replyTo; + } + + @Override + public void setJMSReplyTo(Destination arg0) throws JMSException { + replyTo = arg0; + } + + @Override + public Destination getJMSDestination() throws JMSException { + return destination; + } + + @Override + public void setJMSDestination(Destination arg0) throws JMSException { + destination = arg0; + } + + @Override + public int getJMSDeliveryMode() throws JMSException { + return deliveryMode; + } + + @Override + public void setJMSDeliveryMode(int arg0) throws JMSException { + deliveryMode = arg0; + } + + @Override + public boolean getJMSRedelivered() throws JMSException { + return redelivered; + } + + @Override + public void setJMSRedelivered(boolean arg0) throws JMSException { + redelivered = arg0; + } + + @Override + public String getJMSType() throws JMSException { + return type; + } + + @Override + public void setJMSType(String arg0) throws JMSException { + type = arg0; + } + + @Override + public long getJMSExpiration() throws JMSException { + return expiration; + } + + @Override + public void setJMSExpiration(long arg0) throws JMSException { + expiration = arg0; + } + + @Override + public int getJMSPriority() throws JMSException { + return priority; + } + + @Override + public void setJMSPriority(int arg0) throws JMSException { + priority = arg0; + } + + @Override + public void clearProperties() throws JMSException { + } + + @Override + public boolean propertyExists(String arg0) throws JMSException { + return false; + } + + @Override + public boolean getBooleanProperty(String arg0) throws JMSException { + return false; + } + + @Override + public byte getByteProperty(String arg0) throws JMSException { + return 0; + } + + @Override + public short getShortProperty(String arg0) throws JMSException { + return 0; + } + + @Override + public int getIntProperty(String arg0) throws JMSException { + return 0; + } + + @Override + public long getLongProperty(String arg0) throws JMSException { + return 0; + } + + @Override + public float getFloatProperty(String arg0) throws JMSException { + return 0; + } + + @Override + public double getDoubleProperty(String arg0) throws JMSException { + return 0; + } + + @Override + public String getStringProperty(String arg0) throws JMSException { + return (String)props.get(arg0); + } + + @Override + public Object getObjectProperty(String arg0) throws JMSException { + return props.get(arg0); + } + + @Override + public Enumeration getPropertyNames() throws JMSException { + return new Vector(props.keySet()).elements(); + } + + @Override + public void setBooleanProperty(String arg0, boolean arg1) throws JMSException { + } + + @Override + public void setByteProperty(String arg0, byte arg1) throws JMSException { + } + + @Override + public void setShortProperty(String arg0, short arg1) throws JMSException { + } + + @Override + public void setIntProperty(String arg0, int arg1) throws JMSException { + } + + @Override + public void setLongProperty(String arg0, long arg1) throws JMSException { + } + + @Override + public void setFloatProperty(String arg0, float arg1) throws JMSException { + } + + @Override + public void setDoubleProperty(String arg0, double arg1) throws JMSException { + } + + @Override + public void setStringProperty(String arg0, String arg1) throws JMSException { + props.put(arg0, arg1); + } + + @Override + public void setObjectProperty(String arg0, Object arg1) throws JMSException { + props.put(arg0, arg1); + } + + @Override + public void acknowledge() throws JMSException { + } + + @Override + public void clearBody() throws JMSException { + } + + @Override + public void setText(String arg0) throws JMSException { + text = arg0; + } + + @Override + public String getText() throws JMSException { + return text; + } + } + + public void testForeignMessage() throws Exception { + + // Receive a message with the JMS API + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(destination); + + // Send the message. + { + ForeignMessage message = new ForeignMessage(); + message.text = "Hello"; + message.setStringProperty("test", "value"); + long timeToLive = 10000L; + long start = System.currentTimeMillis(); + producer.send(message, Session.AUTO_ACKNOWLEDGE, 7, timeToLive); + long end = System.currentTimeMillis(); + + + //validate jms spec 1.1 section 3.4.11 table 3.1 + // JMSDestination, JMSDeliveryMode, JMSExpiration, JMSPriority, JMSMessageID, and JMSTimestamp + //must be set by sending a message. + + assertNotNull(message.getJMSDestination()); + assertEquals(Session.AUTO_ACKNOWLEDGE, message.getJMSDeliveryMode()); + assertTrue(start + timeToLive <= message.getJMSExpiration()); + assertTrue(end + timeToLive >= message.getJMSExpiration()); + assertEquals(7, message.getJMSPriority()); + assertNotNull(message.getJMSMessageID()); + assertTrue(start <= message.getJMSTimestamp()); + assertTrue(end >= message.getJMSTimestamp()); + } + + // Validate message is OK. + { + TextMessage message = (TextMessage)consumer.receive(1000); + assertNotNull(message); + assertEquals("Hello", message.getText()); + assertEquals("value", message.getStringProperty("test")); + } + + assertNull(consumer.receiveNoWait()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSQueueRedeliverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSQueueRedeliverTest.java new file mode 100644 index 0000000000..be8a6f26df --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSQueueRedeliverTest.java @@ -0,0 +1,27 @@ +/** + * 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; + +/** + * + */ +public class JMSQueueRedeliverTest extends JmsTopicRedeliverTest { + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSUsecaseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSUsecaseTest.java new file mode 100644 index 0000000000..d22907a95a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSUsecaseTest.java @@ -0,0 +1,141 @@ +/** + * 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; + +import java.util.Enumeration; + +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.Test; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; + +public class JMSUsecaseTest extends JmsTestSupport { + + public ActiveMQDestination destination; + public int deliveryMode; + public int prefetch; + public byte destinationType; + public boolean durableConsumer; + + public static Test suite() { + return suite(JMSUsecaseTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void initCombosForTestQueueBrowser() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE)}); + } + + public void testQueueBrowser() throws Exception { + + // Send a message to the broker. + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(this.deliveryMode); + sendMessages(session, producer, 5); + producer.close(); + + QueueBrowser browser = session.createBrowser((Queue)destination); + Enumeration enumeration = browser.getEnumeration(); + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + assertTrue(enumeration.hasMoreElements()); + Message m = (Message)enumeration.nextElement(); + assertNotNull(m); + assertEquals("" + i, ((TextMessage)m).getText()); + } + assertFalse(enumeration.hasMoreElements()); + } + + public void initCombosForTestSendReceive() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testSendReceive() throws Exception { + // Send a message to the broker. + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(this.deliveryMode); + MessageConsumer consumer = session.createConsumer(destination); + ActiveMQMessage message = new ActiveMQMessage(); + producer.send(message); + + // Make sure only 1 message was delivered. + assertNotNull(consumer.receive(1000)); + assertNull(consumer.receiveNoWait()); + } + + public void initCombosForTestSendReceiveTransacted() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testSendReceiveTransacted() throws Exception { + // Send a message to the broker. + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + destination = createDestination(session, destinationType); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(this.deliveryMode); + MessageConsumer consumer = session.createConsumer(destination); + producer.send(session.createTextMessage("test")); + + // Message should not be delivered until commit. + assertNull(consumer.receiveNoWait()); + session.commit(); + + // Make sure only 1 message was delivered. + Message message = consumer.receive(1000); + assertNotNull(message); + assertFalse(message.getJMSRedelivered()); + assertNull(consumer.receiveNoWait()); + + // Message should be redelivered is rollback is used. + session.rollback(); + + // Make sure only 1 message was delivered. + message = consumer.receive(2000); + assertNotNull(message); + assertTrue(message.getJMSRedelivered()); + assertNull(consumer.receiveNoWait()); + + // If we commit now, the message should not be redelivered. + session.commit(); + assertNull(consumer.receiveNoWait()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSXAConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSXAConsumerTest.java new file mode 100644 index 0000000000..7deff2732e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JMSXAConsumerTest.java @@ -0,0 +1,50 @@ +/** + * 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; + +import javax.jms.ConnectionFactory; +import junit.framework.Test; + +/* + * allow an XA session to be used as an auto ack session when no XA transaction + * https://issues.apache.org/activemq/browse/AMQ-2659 + */ +public class JMSXAConsumerTest extends JMSConsumerTest { + + public static Test suite() { + return suite(JMSXAConsumerTest.class); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQXAConnectionFactory("vm://localhost"); + } + + // some tests use transactions, these will not work unless an XA transaction is in place + // slip these + public void testPrefetch1MessageNotDispatched() throws Exception { + } + + public void testRedispatchOfUncommittedTx() throws Exception { + } + + public void testRedispatchOfRolledbackTx() throws Exception { + } + + public void testMessageListenerOnMessageCloseUnackedWithPrefetch1StayInQueue() throws Exception { + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsAutoAckListenerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsAutoAckListenerTest.java new file mode 100644 index 0000000000..5f34106ae2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsAutoAckListenerTest.java @@ -0,0 +1,80 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +/** + * + */ +public class JmsAutoAckListenerTest extends TestSupport implements MessageListener { + + private Connection connection; + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + /** + * Tests if acknowleged messages are being consumed. + * + * @throws javax.jms.JMSException + */ + public void testAckedMessageAreConsumed() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("test"); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + + Thread.sleep(10000); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + // Attempt to Consume the message...check if message was acknowledge + consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNull(msg); + + session.close(); + } + + public void onMessage(Message message) { + assertNotNull(message); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsAutoAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsAutoAckTest.java new file mode 100644 index 0000000000..90ee032bbe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsAutoAckTest.java @@ -0,0 +1,80 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +/** + * + */ +public class JmsAutoAckTest extends TestSupport { + + private Connection connection; + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + /** + * Tests if acknowleged messages are being consumed. + * + * @throws javax.jms.JMSException + */ + public void testAckedMessageAreConsumed() throws JMSException { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("test"); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + + // Reset the session. + session.close(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + msg = consumer.receive(1000); + assertNull(msg); + + session.close(); + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsBenchmark.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsBenchmark.java new file mode 100644 index 0000000000..52a70a0791 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsBenchmark.java @@ -0,0 +1,209 @@ +/** + * 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; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Benchmarks the broker by starting many consumer and producers against the + * same destination. Make sure you run with jvm option -server (makes a big + * difference). The tests simulate storing 1000 1k jms messages to see the rate + * of processing msg/sec. + * + * + */ +public class JmsBenchmark extends JmsTestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(JmsBenchmark.class); + + private static final long SAMPLE_DELAY = Integer.parseInt(System.getProperty("SAMPLE_DELAY", "" + 1000 * 5)); + private static final long SAMPLES = Integer.parseInt(System.getProperty("SAMPLES", "10")); + private static final long SAMPLE_DURATION = Integer.parseInt(System.getProperty("SAMPLES_DURATION", "" + 1000 * 60)); + private static final int PRODUCER_COUNT = Integer.parseInt(System.getProperty("PRODUCER_COUNT", "10")); + private static final int CONSUMER_COUNT = Integer.parseInt(System.getProperty("CONSUMER_COUNT", "10")); + + public ActiveMQDestination destination; + + public static Test suite() { + return suite(JmsBenchmark.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(JmsBenchmark.class); + } + + public void initCombos() { + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST")}); + } + + @Override + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://(tcp://localhost:0)?persistent=false")); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws URISyntaxException, IOException { + return new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getServer().getConnectURI()); + } + + /** + * @throws Throwable + */ + public void testConcurrentSendReceive() throws Throwable { + + final Semaphore connectionsEstablished = new Semaphore(1 - (CONSUMER_COUNT + PRODUCER_COUNT)); + final Semaphore workerDone = new Semaphore(1 - (CONSUMER_COUNT + PRODUCER_COUNT)); + final CountDownLatch sampleTimeDone = new CountDownLatch(1); + + final AtomicInteger producedMessages = new AtomicInteger(0); + final AtomicInteger receivedMessages = new AtomicInteger(0); + + final Callable producer = new Callable() { + @Override + public Object call() throws JMSException, InterruptedException { + Connection connection = factory.createConnection(); + connections.add(connection); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + BytesMessage message = session.createBytesMessage(); + message.writeBytes(new byte[1024]); + connection.start(); + connectionsEstablished.release(); + + while (!sampleTimeDone.await(0, TimeUnit.MILLISECONDS)) { + producer.send(message); + producedMessages.incrementAndGet(); + } + + connection.close(); + workerDone.release(); + return null; + } + }; + + final Callable consumer = new Callable() { + @Override + public Object call() throws JMSException, InterruptedException { + Connection connection = factory.createConnection(); + connections.add(connection); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message msg) { + receivedMessages.incrementAndGet(); + } + }); + connection.start(); + + connectionsEstablished.release(); + sampleTimeDone.await(); + + connection.close(); + workerDone.release(); + return null; + } + }; + + final Throwable workerError[] = new Throwable[1]; + for (int i = 0; i < PRODUCER_COUNT; i++) { + new Thread("Producer:" + i) { + @Override + public void run() { + try { + producer.call(); + } catch (Throwable e) { + e.printStackTrace(); + workerError[0] = e; + } + } + }.start(); + } + + for (int i = 0; i < CONSUMER_COUNT; i++) { + new Thread("Consumer:" + i) { + @Override + public void run() { + try { + consumer.call(); + } catch (Throwable e) { + e.printStackTrace(); + workerError[0] = e; + } + } + }.start(); + } + + LOG.info(getName() + ": Waiting for Producers and Consumers to startup."); + connectionsEstablished.acquire(); + LOG.info("Producers and Consumers are now running. Waiting for system to reach steady state: " + (SAMPLE_DELAY / 1000.0f) + " seconds"); + Thread.sleep(1000 * 10); + + LOG.info("Starting sample: " + SAMPLES + " each lasting " + (SAMPLE_DURATION / 1000.0f) + " seconds"); + + for (int i = 0; i < SAMPLES; i++) { + + long start = System.currentTimeMillis(); + producedMessages.set(0); + receivedMessages.set(0); + + Thread.sleep(SAMPLE_DURATION); + + long end = System.currentTimeMillis(); + int r = receivedMessages.get(); + int p = producedMessages.get(); + + LOG.info("published: " + p + " msgs at " + (p * 1000f / (end - start)) + " msgs/sec, " + "consumed: " + r + " msgs at " + (r * 1000f / (end - start)) + " msgs/sec"); + } + + LOG.info("Sample done."); + sampleTimeDone.countDown(); + + workerDone.acquire(); + if (workerError[0] != null) { + throw workerError[0]; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsClientAckListenerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsClientAckListenerTest.java new file mode 100644 index 0000000000..c1228077c6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsClientAckListenerTest.java @@ -0,0 +1,130 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +/** + * + */ +public class JmsClientAckListenerTest extends TestSupport implements MessageListener { + + private Connection connection; + private boolean dontAck; + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + /** + * Tests if acknowleged messages are being consumed. + * + * @throws javax.jms.JMSException + */ + public void testAckedMessageAreConsumed() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("test"); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + + Thread.sleep(10000); + + // Reset the session. + session.close(); + + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNull(msg); + + session.close(); + } + + /** + * Tests if unacknowleged messages are being redelivered when the consumer + * connects again. + * + * @throws javax.jms.JMSException + */ + public void testUnAckedMessageAreNotConsumedOnSessionClose() throws Exception { + connection.start(); + // don't aknowledge message on onMessage() call + dontAck = true; + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("test"); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + // Don't ack the message. + + // Reset the session. This should cause the Unacked message to be + // redelivered. + session.close(); + + Thread.sleep(10000); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + Message msg = consumer.receive(2000); + assertNotNull(msg); + msg.acknowledge(); + + session.close(); + } + + public void onMessage(Message message) { + + assertNotNull(message); + if (!dontAck) { + try { + message.acknowledge(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsClientAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsClientAckTest.java new file mode 100644 index 0000000000..ef33f9ac20 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsClientAckTest.java @@ -0,0 +1,151 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +/** + * + */ +public class JmsClientAckTest extends TestSupport { + + private Connection connection; + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + /** + * Tests if acknowledged messages are being consumed. + * + * @throws JMSException + */ + public void testAckedMessageAreConsumed() throws JMSException { + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue(getQueueName()); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + msg.acknowledge(); + + // Reset the session. + session.close(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + msg = consumer.receive(1000); + assertNull(msg); + + session.close(); + } + + /** + * Tests if acknowledged messages are being consumed. + * + * @throws JMSException + */ + public void testLastMessageAcked() throws JMSException { + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue(getQueueName()); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + producer.send(session.createTextMessage("Hello2")); + producer.send(session.createTextMessage("Hello3")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + msg = consumer.receive(1000); + assertNotNull(msg); + msg = consumer.receive(1000); + assertNotNull(msg); + msg.acknowledge(); + + // Reset the session. + session.close(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + msg = consumer.receive(1000); + assertNull(msg); + + session.close(); + } + + /** + * Tests if unacknowledged messages are being re-delivered when the consumer connects again. + * + * @throws JMSException + */ + public void testUnAckedMessageAreNotConsumedOnSessionClose() throws JMSException { + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue(getQueueName()); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + // Don't ack the message. + + // Reset the session. This should cause the unacknowledged message to be re-delivered. + session.close(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + msg = consumer.receive(2000); + assertNotNull(msg); + msg.acknowledge(); + + session.close(); + } + + protected String getQueueName() { + return getClass().getName() + "." + getName(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsConnectionStartStopTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsConnectionStartStopTest.java new file mode 100644 index 0000000000..c972b1e0d7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsConnectionStartStopTest.java @@ -0,0 +1,158 @@ +/** + * 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; + +import java.util.Random; +import java.util.Vector; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +/** + * + */ +public class JmsConnectionStartStopTest extends TestSupport { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(JmsConnectionStartStopTest.class); + + private Connection startedConnection; + private Connection stoppedConnection; + + /** + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + + LOG.info(getClass().getClassLoader().getResource("log4j.properties")); + + ActiveMQConnectionFactory factory = createConnectionFactory(); + startedConnection = factory.createConnection(); + startedConnection.start(); + stoppedConnection = factory.createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + stoppedConnection.close(); + startedConnection.close(); + } + + /** + * Tests if the consumer receives the messages that were sent before the + * connection was started. + * + * @throws JMSException + */ + public void testStoppedConsumerHoldsMessagesTillStarted() throws JMSException { + Session startedSession = startedConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session stoppedSession = stoppedConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Setup the consumers. + Topic topic = startedSession.createTopic("test"); + MessageConsumer startedConsumer = startedSession.createConsumer(topic); + MessageConsumer stoppedConsumer = stoppedSession.createConsumer(topic); + + // Send the message. + MessageProducer producer = startedSession.createProducer(topic); + TextMessage message = startedSession.createTextMessage("Hello"); + producer.send(message); + + // Test the assertions. + Message m = startedConsumer.receive(1000); + assertNotNull(m); + + m = stoppedConsumer.receive(1000); + assertNull(m); + + stoppedConnection.start(); + m = stoppedConsumer.receive(5000); + assertNotNull(m); + + startedSession.close(); + stoppedSession.close(); + } + + /** + * Tests if the consumer is able to receive messages eveb when the + * connecction restarts multiple times. + * + * @throws Exception + */ + public void testMultipleConnectionStops() throws Exception { + testStoppedConsumerHoldsMessagesTillStarted(); + stoppedConnection.stop(); + testStoppedConsumerHoldsMessagesTillStarted(); + stoppedConnection.stop(); + testStoppedConsumerHoldsMessagesTillStarted(); + } + + + public void testConcurrentSessionCreateWithStart() throws Exception { + ThreadPoolExecutor executor = new ThreadPoolExecutor(50, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue()); + final Vector exceptions = new Vector(); + final Random rand = new Random(); + Runnable createSessionTask = new Runnable() { + @Override + public void run() { + try { + TimeUnit.MILLISECONDS.sleep(rand.nextInt(10)); + stoppedConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } catch (Exception e) { + exceptions.add(e); + } + } + }; + + Runnable startStopTask = new Runnable() { + @Override + public void run() { + try { + TimeUnit.MILLISECONDS.sleep(rand.nextInt(10)); + stoppedConnection.start(); + stoppedConnection.stop(); + } catch (Exception e) { + exceptions.add(e); + } + } + }; + + for (int i=0; i<1000; i++) { + executor.execute(createSessionTask); + executor.execute(startStopTask); + } + + executor.shutdown(); + assertTrue("executor terminated", executor.awaitTermination(30, TimeUnit.SECONDS)); + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsConsumerResetActiveListenerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsConsumerResetActiveListenerTest.java new file mode 100644 index 0000000000..1a1a95890c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsConsumerResetActiveListenerTest.java @@ -0,0 +1,151 @@ +/** + * 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; + +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + + +public class JmsConsumerResetActiveListenerTest extends TestCase { + + private Connection connection; + private ActiveMQConnectionFactory factory; + + protected void setUp() throws Exception { + factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = factory.createConnection(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + } + + /** + * verify the (undefined by spec) behaviour of setting a listener while receiving a message. + * + * @throws Exception + */ + public void testSetListenerFromListener() throws Exception { + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination dest = session.createQueue("Queue-" + getName()); + final MessageConsumer consumer = session.createConsumer(dest); + + final CountDownLatch latch = new CountDownLatch(2); + final AtomicBoolean first = new AtomicBoolean(true); + final Vector results = new Vector(); + consumer.setMessageListener(new MessageListener() { + + public void onMessage(Message message) { + if (first.compareAndSet(true, false)) { + try { + consumer.setMessageListener(this); + results.add(message); + } catch (JMSException e) { + results.add(e); + } + } else { + results.add(message); + } + latch.countDown(); + } + }); + + connection.start(); + + MessageProducer producer = session.createProducer(dest); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("First")); + producer.send(session.createTextMessage("Second")); + + assertTrue("we did not timeout", latch.await(5, TimeUnit.SECONDS)); + + assertEquals("we have a result", 2, results.size()); + Object result = results.get(0); + assertTrue(result instanceof TextMessage); + assertEquals("result is first", "First", ((TextMessage)result).getText()); + result = results.get(1); + assertTrue(result instanceof TextMessage); + assertEquals("result is first", "Second", ((TextMessage)result).getText()); + } + + /** + * and a listener on a new consumer, just in case. + * + * @throws Exception + */ + public void testNewConsumerSetListenerFromListener() throws Exception { + final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final Destination dest = session.createQueue("Queue-" + getName()); + final MessageConsumer consumer = session.createConsumer(dest); + + final CountDownLatch latch = new CountDownLatch(2); + final AtomicBoolean first = new AtomicBoolean(true); + final Vector results = new Vector(); + consumer.setMessageListener(new MessageListener() { + + public void onMessage(Message message) { + if (first.compareAndSet(true, false)) { + try { + MessageConsumer anotherConsumer = session.createConsumer(dest); + anotherConsumer.setMessageListener(this); + results.add(message); + } catch (JMSException e) { + results.add(e); + } + } else { + results.add(message); + } + latch.countDown(); + } + }); + + connection.start(); + + MessageProducer producer = session.createProducer(dest); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("First")); + producer.send(session.createTextMessage("Second")); + + assertTrue("we did not timeout", latch.await(5, TimeUnit.SECONDS)); + + assertEquals("we have a result", 2, results.size()); + Object result = results.get(0); + assertTrue(result instanceof TextMessage); + assertEquals("result is first", "First", ((TextMessage)result).getText()); + result = results.get(1); + assertTrue(result instanceof TextMessage); + assertEquals("result is first", "Second", ((TextMessage)result).getText()); + } + } diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsCreateConsumerInOnMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsCreateConsumerInOnMessageTest.java new file mode 100644 index 0000000000..7a219e2cc3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsCreateConsumerInOnMessageTest.java @@ -0,0 +1,99 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; + +/** + * + */ +public class JmsCreateConsumerInOnMessageTest extends TestSupport implements MessageListener { + + private Connection connection; + private Session publisherSession; + private Session consumerSession; + private MessageConsumer consumer; + private MessageConsumer testConsumer; + private MessageProducer producer; + private Topic topic; + private Object lock = new Object(); + + /* + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + super.topic = true; + connection = createConnection(); + connection.setClientID("connection:" + getSubject()); + publisherSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = (Topic)super.createDestination("Test.Topic"); + consumer = consumerSession.createConsumer(topic); + consumer.setMessageListener(this); + producer = publisherSession.createProducer(topic); + connection.start(); + } + + /* + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + connection.close(); + } + + /** + * Tests if a consumer can be created asynchronusly + * + * @throws Exception + */ + public void testCreateConsumer() throws Exception { + Message msg = super.createMessage(); + producer.send(msg); + if (testConsumer == null) { + synchronized (lock) { + lock.wait(3000); + } + } + assertTrue(testConsumer != null); + } + + /** + * Use the asynchronous subscription mechanism + * + * @param message + */ + public void onMessage(Message message) { + try { + testConsumer = consumerSession.createConsumer(topic); + consumerSession.createProducer(topic); + synchronized (lock) { + lock.notify(); + } + } catch (Exception ex) { + ex.printStackTrace(); + assertTrue(false); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableQueueWildcardSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableQueueWildcardSendReceiveTest.java new file mode 100644 index 0000000000..72dd8bcbd7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableQueueWildcardSendReceiveTest.java @@ -0,0 +1,52 @@ +/** + * 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; + +import javax.jms.DeliveryMode; + +import org.apache.activemq.test.JmsTopicSendReceiveTest; + +/** + * + */ +public class JmsDurableQueueWildcardSendReceiveTest extends JmsTopicSendReceiveTest { + + /** + * Set up the test with a queue and persistent delivery mode. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + topic = false; + deliveryMode = DeliveryMode.PERSISTENT; + super.setUp(); + } + + /** + * Returns the consumer subject. + */ + protected String getConsumerSubject() { + return "FOO.>"; + } + + /** + * Returns the producer subject. + */ + protected String getProducerSubject() { + return "FOO.BAR.HUMBUG"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicSelectorTest.java new file mode 100644 index 0000000000..cc212ab903 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicSelectorTest.java @@ -0,0 +1,27 @@ +/** + * 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; + +/** + * + */ +public class JmsDurableTopicSelectorTest extends JmsTopicSelectorTest { + public void setUp() throws Exception { + durable = true; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicSendReceiveTest.java new file mode 100644 index 0000000000..fa47ea9ede --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicSendReceiveTest.java @@ -0,0 +1,90 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.test.JmsTopicSendReceiveTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsDurableTopicSendReceiveTest extends JmsTopicSendReceiveTest { + private static final Logger LOG = LoggerFactory.getLogger(JmsDurableTopicSendReceiveTest.class); + + protected Connection connection2; + protected Session session2; + protected Session consumeSession2; + protected MessageConsumer consumer2; + protected MessageProducer producer2; + protected Destination consumerDestination2; + protected Destination producerDestination2; + + /** + * Set up a durable suscriber test. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + this.durable = true; + super.setUp(); + } + + /** + * Test if all the messages sent are being received. + * + * @throws Exception + */ + public void testSendWhileClosed() throws Exception { + connection2 = createConnection(); + connection2.setClientID("test"); + connection2.start(); + session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer2 = session2.createProducer(null); + producer2.setDeliveryMode(deliveryMode); + producerDestination2 = session2.createTopic(getProducerSubject() + "2"); + Thread.sleep(1000); + + consumeSession2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerDestination2 = session2.createTopic(getConsumerSubject() + "2"); + consumer2 = consumeSession2.createDurableSubscriber((Topic)consumerDestination2, getName()); + Thread.sleep(1000); + consumer2.close(); + TextMessage message = session2.createTextMessage("test"); + message.setStringProperty("test", "test"); + message.setJMSType("test"); + producer2.send(producerDestination2, message); + LOG.info("Creating durable consumer"); + consumer2 = consumeSession2.createDurableSubscriber((Topic)consumerDestination2, getName()); + Message msg = consumer2.receive(1000); + assertNotNull(msg); + assertEquals(((TextMessage)msg).getText(), "test"); + assertEquals(msg.getJMSType(), "test"); + assertEquals(msg.getStringProperty("test"), "test"); + connection2.stop(); + connection2.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicTransactionTest.java new file mode 100644 index 0000000000..c01fb7f1ef --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicTransactionTest.java @@ -0,0 +1,40 @@ +/** + * 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; + +import javax.jms.DeliveryMode; + +import org.apache.activemq.test.JmsResourceProvider; + +/** + * + */ +public class JmsDurableTopicTransactionTest extends JmsTopicTransactionTest { + + /** + * @see JmsTransactionTestSupport#getJmsResourceProvider() + */ + protected JmsResourceProvider getJmsResourceProvider() { + JmsResourceProvider provider = new JmsResourceProvider(); + provider.setTopic(true); + provider.setDeliveryMode(DeliveryMode.PERSISTENT); + provider.setClientID(getClass().getName()); + provider.setDurableName(getName()); + return provider; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicWildcardSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicWildcardSendReceiveTest.java new file mode 100644 index 0000000000..3058a574df --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsDurableTopicWildcardSendReceiveTest.java @@ -0,0 +1,54 @@ +/** + * 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; + +import javax.jms.DeliveryMode; + +import org.apache.activemq.test.JmsTopicSendReceiveTest; + +/** + * + */ +public class JmsDurableTopicWildcardSendReceiveTest extends JmsTopicSendReceiveTest { + + /** + * Sets up a test with a topic destination, durable suscriber and persistent + * delivery mode. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + topic = true; + durable = true; + deliveryMode = DeliveryMode.PERSISTENT; + super.setUp(); + } + + /** + * Returns the consumer subject. + */ + protected String getConsumerSubject() { + return "FOO.>"; + } + + /** + * Returns the producer subject. + */ + protected String getProducerSubject() { + return "FOO.BAR.HUMBUG"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMessageConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMessageConsumerTest.java new file mode 100644 index 0000000000..908de0dfa7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMessageConsumerTest.java @@ -0,0 +1,170 @@ +/** + * 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; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class JmsMessageConsumerTest { + + private BrokerService brokerService; + private String brokerURI; + + @Rule public TestName name = new TestName(); + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(false); + brokerService.start(); + brokerService.waitUntilStarted(); + + brokerURI = "vm://localhost?create=false"; + } + + @After + public void stopBroker() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + @Test + public void testSyncReceiveWithExpirationChecks() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(name.getMethodName()); + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(TimeUnit.SECONDS.toMillis(2)); + connection.start(); + + producer.send(session.createTextMessage("test")); + + // Allow message to expire in the prefetch buffer + TimeUnit.SECONDS.sleep(4); + + assertNull(consumer.receive(1000)); + connection.close(); + } + + @Test + public void testSyncReceiveWithIgnoreExpirationChecks() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI); + factory.setConsumerExpiryCheckEnabled(false); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(name.getMethodName()); + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(TimeUnit.SECONDS.toMillis(2)); + connection.start(); + + producer.send(session.createTextMessage("test")); + + // Allow message to expire in the prefetch buffer + TimeUnit.SECONDS.sleep(4); + + assertNotNull(consumer.receive(1000)); + connection.close(); + } + + @Test + public void testAsyncReceiveWithExpirationChecks() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI); + + final CountDownLatch received = new CountDownLatch(1); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(name.getMethodName()); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + received.countDown(); + } + }); + MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(TimeUnit.SECONDS.toMillis(2)); + + producer.send(session.createTextMessage("test")); + + // Allow message to expire in the prefetch buffer + TimeUnit.SECONDS.sleep(4); + connection.start(); + + assertFalse(received.await(1, TimeUnit.SECONDS)); + connection.close(); + } + + @Test + public void testAsyncReceiveWithoutExpirationChecks() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI); + factory.setConsumerExpiryCheckEnabled(false); + + final CountDownLatch received = new CountDownLatch(1); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(name.getMethodName()); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + received.countDown(); + } + }); + MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(TimeUnit.SECONDS.toMillis(2)); + + producer.send(session.createTextMessage("test")); + + // Allow message to expire in the prefetch buffer + TimeUnit.SECONDS.sleep(4); + connection.start(); + + assertTrue(received.await(5, TimeUnit.SECONDS)); + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMultipleBrokersTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMultipleBrokersTestSupport.java new file mode 100644 index 0000000000..1d994b9af1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMultipleBrokersTestSupport.java @@ -0,0 +1,641 @@ +/** + * 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; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.advisory.ConsumerEvent; +import org.apache.activemq.advisory.ConsumerEventSource; +import org.apache.activemq.advisory.ConsumerListener; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.TopicRegion; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkBridge; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.IdGenerator; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.Wait; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; + +/** + * Test case support that allows the easy management and connection of several + * brokers. + * + * + */ +public class JmsMultipleBrokersTestSupport extends CombinationTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(JmsMultipleBrokersTestSupport.class); + public static final String AUTO_ASSIGN_TRANSPORT = "tcp://localhost:0"; + public static int maxSetupTime = 5000; + + protected Map brokers; + protected Map destinations; + + protected int messageSize = 1; + + protected boolean persistentDelivery = true; + protected boolean verbose; + + protected NetworkConnector bridgeBrokers(String localBrokerName, String remoteBrokerName) throws Exception { + return bridgeBrokers(localBrokerName, remoteBrokerName, false, 1, true); + } + + protected NetworkConnector bridgeBrokers(String localBrokerName, String remoteBrokerName, boolean dynamicOnly) throws Exception { + BrokerService localBroker = brokers.get(localBrokerName).broker; + BrokerService remoteBroker = brokers.get(remoteBrokerName).broker; + + return bridgeBrokers(localBroker, remoteBroker, dynamicOnly, 1, true, false); + } + + protected NetworkConnector bridgeBrokers(String localBrokerName, String remoteBrokerName, boolean dynamicOnly, int networkTTL, boolean conduit) throws Exception { + BrokerService localBroker = brokers.get(localBrokerName).broker; + BrokerService remoteBroker = brokers.get(remoteBrokerName).broker; + + return bridgeBrokers(localBroker, remoteBroker, dynamicOnly, networkTTL, conduit, false); + } + + // Overwrite this method to specify how you want to bridge the two brokers + // By default, bridge them using add network connector of the local broker + // and the first connector of the remote broker + protected NetworkConnector bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker, boolean dynamicOnly, int networkTTL, boolean conduit, boolean failover) throws Exception { + List transportConnectors = remoteBroker.getTransportConnectors(); + URI remoteURI; + if (!transportConnectors.isEmpty()) { + remoteURI = transportConnectors.get(0).getConnectUri(); + String uri = "static:(" + remoteURI + ")"; + if (failover) { + uri = "static:(failover:(" + remoteURI + "))"; + } + NetworkConnector connector = new DiscoveryNetworkConnector(new URI(uri)); + connector.setName("to-" + remoteBroker.getBrokerName()); + connector.setDynamicOnly(dynamicOnly); + connector.setNetworkTTL(networkTTL); + connector.setConduitSubscriptions(conduit); + localBroker.addNetworkConnector(connector); + maxSetupTime = 2000; + return connector; + } else { + throw new Exception("Remote broker has no registered connectors."); + } + + } + + // This will interconnect all brokers using multicast + protected void bridgeAllBrokers() throws Exception { + bridgeAllBrokers("default", 1, false, false); + } + + protected void bridgeAllBrokers(String groupName, int ttl, boolean suppressduplicateQueueSubs) throws Exception { + bridgeAllBrokers(groupName, ttl, suppressduplicateQueueSubs, false); + } + + protected void bridgeAllBrokers(String groupName, int ttl, boolean suppressduplicateQueueSubs, boolean decreasePriority) throws Exception { + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + List transportConnectors = broker.getTransportConnectors(); + + if (transportConnectors.isEmpty()) { + broker.addConnector(new URI(AUTO_ASSIGN_TRANSPORT)); + transportConnectors = broker.getTransportConnectors(); + } + + TransportConnector transport = transportConnectors.get(0); + transport.setDiscoveryUri(new URI("multicast://default?group=" + groupName)); + NetworkConnector nc = broker.addNetworkConnector("multicast://default?group=" + groupName); + nc.setNetworkTTL(ttl); + nc.setSuppressDuplicateQueueSubscriptions(suppressduplicateQueueSubs); + nc.setDecreaseNetworkConsumerPriority(decreasePriority); + } + + // Multicasting may take longer to setup + maxSetupTime = 8000; + } + + + protected void waitForBridgeFormation(final int min) throws Exception { + for (BrokerItem brokerItem : brokers.values()) { + final BrokerService broker = brokerItem.broker; + waitForBridgeFormation(broker, min, 0); + } + } + + public boolean waitForBridgeFormation(final BrokerService broker, final int min, final int bridgeIndex) throws Exception { + return waitForBridgeFormation(broker, min, bridgeIndex, Wait.MAX_WAIT_MILLIS*2); + } + + public boolean waitForBridgeFormation(final BrokerService broker, final int min, final int bridgeIndex, long wait) throws Exception { + + boolean result = false; + if (!broker.getNetworkConnectors().isEmpty()) { + result = Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + int activeCount = 0; + for (NetworkBridge bridge : broker.getNetworkConnectors().get(bridgeIndex).activeBridges()) { + if (bridge.getRemoteBrokerName() != null) { + LOG.info("found bridge[" + bridge + "] to " + bridge.getRemoteBrokerName() + " on broker :" + broker.getBrokerName()); + activeCount++; + } + } + return activeCount >= min; + }}, wait); + } + return result; + } + + protected void waitForMinTopicRegionConsumerCount(final String name, final int count) throws Exception { + final BrokerService broker = brokers.get(name).broker; + final TopicRegion topicRegion = (TopicRegion) ((RegionBroker) broker.getRegionBroker()).getTopicRegion(); + assertTrue("found expected consumers in topic region of" + name, Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("topic consumers: " + name +", " + topicRegion.getSubscriptions().toString()); + return topicRegion.getSubscriptions().size() >= count; + } + })); + } + + /** + * Timed wait for {@link #hasBridge(String, String)}. + * + * @see #hasBridge(String, String) + * + * @param localBrokerName + * - the name of the broker on the "local" side of the bridge + * @param remoteBrokerName + * - the name of the broker on the "remote" side of the bridge + * @param time + * - the maximum time to wait for the bridge to be established + * @param units + * - the units for time + * @throws InterruptedException + * - if the calling thread is interrupted + * @throws TimeoutException + * - if the bridge is not established within the time limit + * @throws Exception + * - some other unknown error occurs + */ + protected void waitForBridge(final String localBrokerName, + final String remoteBrokerName, long time, TimeUnit units) + throws InterruptedException, TimeoutException, Exception { + if (!Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() { + return hasBridge(localBrokerName, remoteBrokerName); + } + }, units.toMillis(time))) { + throw new TimeoutException("Bridge not established from broker " + + localBrokerName + " to " + remoteBrokerName + " within " + + units.toMillis(time) + " milliseconds."); + } + } + + /** + * Determines whether a bridge has been established between the specified + * brokers.Establishment means that connections have been created and broker + * info has been exchanged. Due to the asynchronous nature of the + * connections, there is still a possibility that the bridge may fail + * shortly after establishment. + * + * @param localBrokerName + * - the name of the broker on the "local" side of the bridge + * @param remoteBrokerName + * - the name of the broker on the "remote" side of the bridge + */ + protected boolean hasBridge(String localBrokerName, String remoteBrokerName) { + final BrokerItem fromBroker = brokers.get(localBrokerName); + if (fromBroker == null) { + throw new IllegalArgumentException("Unknown broker: " + + localBrokerName); + } + + for (BrokerInfo peerInfo : fromBroker.broker.getRegionBroker() + .getPeerBrokerInfos()) { + if (peerInfo.getBrokerName().equals(remoteBrokerName)) { + return true; + } + } + return false; + } + + protected void waitForBridgeFormation() throws Exception { + waitForBridgeFormation(1); + } + + protected void startAllBrokers() throws Exception { + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + broker.start(); + broker.waitUntilStarted(); + } + + Thread.sleep(maxSetupTime); + } + + protected BrokerService createBroker(String brokerName) throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName(brokerName); + brokers.put(brokerName, new BrokerItem(broker)); + + return broker; + } + + protected BrokerService createBroker(URI brokerUri) throws Exception { + BrokerService broker = BrokerFactory.createBroker(brokerUri); + configureBroker(broker); + brokers.put(broker.getBrokerName(), new BrokerItem(broker)); + + return broker; + } + + protected void configureBroker(BrokerService broker) { + } + + protected BrokerService createBroker(Resource configFile) throws Exception { + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(configFile); + brokerFactory.afterPropertiesSet(); + + BrokerService broker = brokerFactory.getBroker(); + brokers.put(broker.getBrokerName(), new BrokerItem(broker)); + + return broker; + } + + protected ConnectionFactory getConnectionFactory(String brokerName) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + return brokerItem.factory; + } + return null; + } + + protected Connection createConnection(String brokerName) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + return brokerItem.createConnection(); + } + return null; + } + + protected MessageConsumer createSyncConsumer(String brokerName, Destination dest) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + Connection con = brokerItem.createConnection(); + con.start(); + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = sess.createConsumer(dest); + return consumer; + } + return null; + } + + protected MessageConsumer createConsumer(String brokerName, Destination dest) throws Exception { + return createConsumer(brokerName, dest, null, null); + } + + protected MessageConsumer createConsumer(String brokerName, Destination dest, String messageSelector) throws Exception { + return createConsumer(brokerName, dest, null, messageSelector); + } + + protected MessageConsumer createConsumer(String brokerName, Destination dest, CountDownLatch latch) throws Exception { + return createConsumer(brokerName, dest, latch, null); + } + + protected MessageConsumer createConsumer(String brokerName, Destination dest, CountDownLatch latch, String messageSelector) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + return brokerItem.createConsumer(dest, latch, messageSelector); + } + return null; + } + + protected QueueBrowser createBrowser(String brokerName, Destination dest) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + return brokerItem.createBrowser(dest); + } + return null; + } + + protected MessageConsumer createDurableSubscriber(String brokerName, Topic dest, String name) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + return brokerItem.createDurableSubscriber(dest, name); + } + return null; + } + + protected MessageIdList getBrokerMessages(String brokerName) { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + return brokerItem.getAllMessages(); + } + return null; + } + + protected MessageIdList getConsumerMessages(String brokerName, MessageConsumer consumer) { + BrokerItem brokerItem = brokers.get(brokerName); + if (brokerItem != null) { + return brokerItem.getConsumerMessages(consumer); + } + return null; + } + + protected void assertConsumersConnect(String brokerName, Destination destination, final int count, long timeout) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + Connection conn = brokerItem.createConnection(); + conn.start(); + ConsumerEventSource ces = new ConsumerEventSource(conn, destination); + + try { + final AtomicInteger actualConnected = new AtomicInteger(); + final CountDownLatch latch = new CountDownLatch(1); + ces.setConsumerListener(new ConsumerListener(){ + public void onConsumerEvent(ConsumerEvent event) { + if( actualConnected.get() < count ) { + actualConnected.set(event.getConsumerCount()); + } + if( event.getConsumerCount() >= count ) { + latch.countDown(); + } + } + }); + ces.start(); + + latch.await(timeout, TimeUnit.MILLISECONDS); + assertTrue("Expected at least "+count+" consumers to connect, but only "+actualConnected.get()+" connectect within "+timeout+" ms", actualConnected.get() >= count); + + } finally { + ces.stop(); + conn.close(); + brokerItem.connections.remove(conn); + } + } + + + protected void sendMessages(String brokerName, Destination destination, int count) throws Exception { + sendMessages(brokerName, destination, count, null); + } + + protected void sendMessages(String brokerName, Destination destination, int count, HashMapproperties) throws Exception { + BrokerItem brokerItem = brokers.get(brokerName); + + Connection conn = brokerItem.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = brokerItem.createProducer(destination, sess); + producer.setDeliveryMode(persistentDelivery ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + for (int i = 0; i < count; i++) { + TextMessage msg = createTextMessage(sess, conn.getClientID() + ": Message-" + i); + if (properties != null) { + for (String propertyName : properties.keySet()) { + msg.setObjectProperty(propertyName, properties.get(propertyName)); + } + } + producer.send(msg); + onSend(i, msg); + } + + producer.close(); + sess.close(); + conn.close(); + brokerItem.connections.remove(conn); + } + + protected void onSend(int i, TextMessage msg) { + } + + protected TextMessage createTextMessage(Session session, String initText) throws Exception { + TextMessage msg = session.createTextMessage(); + + // Pad message text + if (initText.length() < messageSize) { + char[] data = new char[messageSize - initText.length()]; + Arrays.fill(data, '*'); + String str = new String(data); + msg.setText(initText + str); + + // Do not pad message text + } else { + msg.setText(initText); + } + + return msg; + } + + protected ActiveMQDestination createDestination(String name, boolean topic) throws JMSException { + Destination dest; + if (topic) { + dest = new ActiveMQTopic(name); + destinations.put(name, dest); + return (ActiveMQDestination)dest; + } else { + dest = new ActiveMQQueue(name); + destinations.put(name, dest); + return (ActiveMQDestination)dest; + } + } + + protected void setUp() throws Exception { + super.setUp(); + brokers = new HashMap(); + destinations = new HashMap(); + } + + protected void tearDown() throws Exception { + destroyAllBrokers(); + super.tearDown(); + } + + protected void destroyBroker(String brokerName) throws Exception { + BrokerItem brokerItem = brokers.remove(brokerName); + + if (brokerItem != null) { + brokerItem.destroy(); + } + } + + protected void destroyAllBrokers() throws Exception { + for (Iterator i = brokers.values().iterator(); i.hasNext();) { + BrokerItem brokerItem = i.next(); + brokerItem.destroy(); + } + brokers.clear(); + } + + // Class to group broker components together + public class BrokerItem { + public BrokerService broker; + public ActiveMQConnectionFactory factory; + public List connections; + public Map consumers; + public MessageIdList allMessages = new MessageIdList(); + public boolean persistent; + private IdGenerator id; + + public BrokerItem(BrokerService broker) throws Exception { + this.broker = broker; + + factory = new ActiveMQConnectionFactory(broker.getVmConnectorURI()); + factory.setConnectionIDPrefix(broker.getBrokerName()); + consumers = Collections.synchronizedMap(new HashMap()); + connections = Collections.synchronizedList(new ArrayList()); + allMessages.setVerbose(verbose); + id = new IdGenerator(broker.getBrokerName() + ":"); + } + + public Connection createConnection() throws Exception { + Connection conn = factory.createConnection(); + conn.setClientID(id.generateId()); + + connections.add(conn); + return conn; + } + + public MessageConsumer createConsumer(Destination dest) throws Exception { + return createConsumer(dest, null, null); + } + + public MessageConsumer createConsumer(Destination dest, String messageSelector) throws Exception { + return createConsumer(dest, null, messageSelector); + } + + public MessageConsumer createConsumer(Destination dest, CountDownLatch latch, String messageSelector) throws Exception { + Connection c = createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + return createConsumerWithSession(dest, s, latch, messageSelector); + } + + public MessageConsumer createConsumerWithSession(Destination dest, Session sess) throws Exception { + return createConsumerWithSession(dest, sess, null, null); + } + + public MessageConsumer createConsumerWithSession(Destination dest, Session sess, CountDownLatch latch, String messageSelector) throws Exception { + MessageConsumer client = sess.createConsumer(dest, messageSelector); + MessageIdList messageIdList = new MessageIdList(); + messageIdList.setCountDownLatch(latch); + messageIdList.setParent(allMessages); + client.setMessageListener(messageIdList); + consumers.put(client, messageIdList); + return client; + } + + public QueueBrowser createBrowser(Destination dest) throws Exception { + Connection c = createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + return s.createBrowser((Queue)dest); + } + + public MessageConsumer createDurableSubscriber(Topic dest, String name) throws Exception { + Connection c = createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + return createDurableSubscriber(dest, s, name); + } + + public MessageConsumer createDurableSubscriber(Topic dest, Session sess, String name) throws Exception { + MessageConsumer client = sess.createDurableSubscriber((Topic)dest, name); + MessageIdList messageIdList = new MessageIdList(); + messageIdList.setParent(allMessages); + client.setMessageListener(messageIdList); + consumers.put(client, messageIdList); + + return client; + } + + public MessageIdList getAllMessages() { + return allMessages; + } + + public MessageIdList getConsumerMessages(MessageConsumer consumer) { + return consumers.get(consumer); + } + + public MessageProducer createProducer(Destination dest) throws Exception { + Connection c = createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + return createProducer(dest, s); + } + + public MessageProducer createProducer(Destination dest, Session sess) throws Exception { + MessageProducer client = sess.createProducer(dest); + client.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + return client; + } + + public void destroy() throws Exception { + while (!connections.isEmpty()) { + Connection c = connections.remove(0); + try { + c.close(); + } catch (ConnectionClosedException e) { + } catch (JMSException e) { + } + } + + broker.stop(); + broker.waitUntilStopped(); + consumers.clear(); + + broker = null; + connections = null; + consumers = null; + factory = null; + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMultipleClientsTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMultipleClientsTestSupport.java new file mode 100644 index 0000000000..5eaab8dda7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsMultipleClientsTestSupport.java @@ -0,0 +1,335 @@ +/** + * 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; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.broker.BrokerFactory; +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.MessageIdList; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.*; + +/** + * Test case support used to test multiple message comsumers and message + * producers connecting to a single broker. + * + * + */ +public class JmsMultipleClientsTestSupport { + + @Rule + public TestName testName = new TestName(); + + protected static final Logger LOG = LoggerFactory.getLogger(JmsMultipleClientsTestSupport.class); + + protected Map consumers = new HashMap(); // Map of consumer with messages + // received + protected int consumerCount = 1; + protected int producerCount = 1; + + protected int messageSize = 1024; + + protected boolean useConcurrentSend = true; + protected boolean autoFail = true; + protected boolean durable; + public boolean topic; + protected boolean persistent; + + protected BrokerService broker; + protected Destination destination; + protected List connections = Collections.synchronizedList(new ArrayList()); + protected MessageIdList allMessagesList = new MessageIdList(); + + private AtomicInteger producerLock; + + protected void startProducers(Destination dest, int msgCount) throws Exception { + startProducers(createConnectionFactory(), dest, msgCount); + } + + protected void startProducers(final ConnectionFactory factory, final Destination dest, final int msgCount) throws Exception { + // Use concurrent send + if (useConcurrentSend) { + producerLock = new AtomicInteger(producerCount); + + for (int i = 0; i < producerCount; i++) { + Thread t = new Thread(new Runnable() { + public void run() { + try { + sendMessages(factory.createConnection(), dest, msgCount); + } catch (Exception e) { + e.printStackTrace(); + } + + synchronized (producerLock) { + producerLock.decrementAndGet(); + producerLock.notifyAll(); + } + } + }); + + t.start(); + } + + // Wait for all producers to finish sending + synchronized (producerLock) { + while (producerLock.get() != 0) { + producerLock.wait(2000); + } + } + + // Use serialized send + } else { + for (int i = 0; i < producerCount; i++) { + sendMessages(factory.createConnection(), dest, msgCount); + } + } + } + + protected void sendMessages(Connection connection, Destination destination, int count) throws Exception { + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + for (int i = 0; i < count; i++) { + TextMessage msg = createTextMessage(session, "" + i); + producer.send(msg); + } + + producer.close(); + session.close(); + connection.close(); + } + + protected TextMessage createTextMessage(Session session, String initText) throws Exception { + TextMessage msg = session.createTextMessage(); + + // Pad message text + if (initText.length() < messageSize) { + char[] data = new char[messageSize - initText.length()]; + Arrays.fill(data, '*'); + String str = new String(data); + msg.setText(initText + str); + + // Do not pad message text + } else { + msg.setText(initText); + } + + return msg; + } + + protected void startConsumers(Destination dest) throws Exception { + startConsumers(createConnectionFactory(), dest); + } + + protected void startConsumers(ConnectionFactory factory, Destination dest) throws Exception { + MessageConsumer consumer; + for (int i = 0; i < consumerCount; i++) { + if (durable && topic) { + consumer = createDurableSubscriber(factory.createConnection(), dest, "consumer" + (i + 1)); + } else { + consumer = createMessageConsumer(factory.createConnection(), dest); + } + MessageIdList list = new MessageIdList(); + list.setParent(allMessagesList); + consumer.setMessageListener(list); + consumers.put(consumer, list); + } + } + + protected MessageConsumer createMessageConsumer(Connection conn, Destination dest) throws Exception { + connections.add(conn); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = sess.createConsumer(dest); + conn.start(); + + return consumer; + } + + protected TopicSubscriber createDurableSubscriber(Connection conn, Destination dest, String name) throws Exception { + conn.setClientID(name); + connections.add(conn); + conn.start(); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSubscriber consumer = sess.createDurableSubscriber((javax.jms.Topic)dest, name); + + return consumer; + } + + protected void waitForAllMessagesToBeReceived(int messageCount) throws Exception { + allMessagesList.waitForMessagesToArrive(messageCount); + } + + protected ActiveMQDestination createDestination() throws JMSException { + String name = "." + getClass().getName() + "." + getName(); + // ensure not inadvertently composite because of combos + name = name.replace(' ','_'); + name = name.replace(',','&'); + if (topic) { + destination = new ActiveMQTopic("Topic" + name); + return (ActiveMQDestination)destination; + } else { + destination = new ActiveMQQueue("Queue" + name); + return (ActiveMQDestination)destination; + } + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost"); + } + + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://()/localhost?persistent=false&useJmx=true")); + } + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + } + + @After + public void tearDown() throws Exception { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection conn = iter.next(); + try { + conn.close(); + } catch (Throwable e) { + } + } + if (broker !=null ) { // FIXME remove + broker.stop(); + allMessagesList.flushMessages(); + consumers.clear(); + } + } + + /* + * Some helpful assertions for multiple consumers. + */ + protected void assertConsumerReceivedAtLeastXMessages(MessageConsumer consumer, int msgCount) { + MessageIdList messageIdList = consumers.get(consumer); + messageIdList.assertAtLeastMessagesReceived(msgCount); + } + + protected void assertConsumerReceivedAtMostXMessages(MessageConsumer consumer, int msgCount) { + MessageIdList messageIdList = consumers.get(consumer); + messageIdList.assertAtMostMessagesReceived(msgCount); + } + + protected void assertConsumerReceivedXMessages(MessageConsumer consumer, int msgCount) { + MessageIdList messageIdList = consumers.get(consumer); + messageIdList.assertMessagesReceivedNoWait(msgCount); + } + + protected void assertEachConsumerReceivedAtLeastXMessages(int msgCount) { + for (Iterator i = consumers.keySet().iterator(); i.hasNext();) { + assertConsumerReceivedAtLeastXMessages(i.next(), msgCount); + } + } + + protected void assertEachConsumerReceivedAtMostXMessages(int msgCount) { + for (Iterator i = consumers.keySet().iterator(); i.hasNext();) { + assertConsumerReceivedAtMostXMessages(i.next(), msgCount); + } + } + + protected void assertEachConsumerReceivedXMessages(int msgCount) { + for (Iterator i = consumers.keySet().iterator(); i.hasNext();) { + assertConsumerReceivedXMessages(i.next(), msgCount); + } + } + + protected void assertTotalMessagesReceived(int msgCount) { + allMessagesList.assertMessagesReceivedNoWait(msgCount); + + // now lets count the individual messages received + int totalMsg = 0; + for (Iterator i = consumers.keySet().iterator(); i.hasNext();) { + MessageIdList messageIdList = consumers.get(i.next()); + totalMsg += messageIdList.getMessageCount(); + } + assertEquals("Total of consumers message count", msgCount, totalMsg); + } + + + public String getName() { + return getName(false); + } + + public String getName(boolean original) { + String currentTestName = testName.getMethodName(); + currentTestName = currentTestName.replace("[",""); + currentTestName = currentTestName.replace("]",""); + return currentTestName; + } + + public void assertDestinationMemoryUsageGoesToZero() throws Exception { + assertEquals("destination memory is back to 0", 0, + TestSupport.getDestination(broker, ActiveMQDestination.transform(destination)).getMemoryUsage().getPercentUsage()); + } + + + + /* + * This is copied from AutoFailTestSupport. We may want to move it to someplace where more + * tests can use it. + */ + public static void dumpAllThreads(String prefix) { + Map stacks = Thread.getAllStackTraces(); + for (Map.Entry stackEntry : stacks.entrySet()) { + System.err.println(prefix + " " + stackEntry.getKey()); + for(StackTraceElement element : stackEntry.getValue()) { + System.err.println(" " + element); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueBrowserTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueBrowserTest.java new file mode 100644 index 0000000000..c063e24fbf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueBrowserTest.java @@ -0,0 +1,448 @@ +/** + * 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; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.BaseDestination; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JmsQueueBrowserTest extends JmsTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(ActiveMQXAConnectionFactoryTest.class); + public boolean isUseCache = false; + + public static Test suite() throws Exception { + return suite(JmsQueueBrowserTest.class); + } + + /** + * Tests the queue browser. Browses the messages then the consumer tries to receive them. The messages should still + * be in the queue even when it was browsed. + * + * @throws Exception + */ + public void testReceiveBrowseReceive() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + + Message[] outbound = new Message[]{session.createTextMessage("First Message"), + session.createTextMessage("Second Message"), + session.createTextMessage("Third Message")}; + + // lets consume any outstanding messages from previous test runs + while (consumer.receive(1000) != null) { + } + + producer.send(outbound[0]); + producer.send(outbound[1]); + producer.send(outbound[2]); + + // Get the first. + assertEquals(outbound[0], consumer.receive(1000)); + consumer.close(); + + QueueBrowser browser = session.createBrowser(destination); + Enumeration enumeration = browser.getEnumeration(); + + // browse the second + assertTrue("should have received the second message", enumeration.hasMoreElements()); + assertEquals(outbound[1], enumeration.nextElement()); + + // browse the third. + assertTrue("Should have received the third message", enumeration.hasMoreElements()); + assertEquals(outbound[2], enumeration.nextElement()); + + // There should be no more. + boolean tooMany = false; + while (enumeration.hasMoreElements()) { + LOG.info("Got extra message: " + ((TextMessage) enumeration.nextElement()).getText()); + tooMany = true; + } + assertFalse(tooMany); + browser.close(); + + // Re-open the consumer. + consumer = session.createConsumer(destination); + // Receive the second. + assertEquals(outbound[1], consumer.receive(1000)); + // Receive the third. + assertEquals(outbound[2], consumer.receive(1000)); + consumer.close(); + } + + public void initCombosForTestBatchSendBrowseReceive() { + addCombinationValues("isUseCache", new Boolean[]{Boolean.TRUE, Boolean.FALSE}); + } + + public void testBatchSendBrowseReceive() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + + TextMessage[] outbound = new TextMessage[10]; + for (int i=0; i<10; i++) { + outbound[i] = session.createTextMessage( i + " Message"); + }; + + // lets consume any outstanding messages from previous test runs + while (consumer.receive(1000) != null) { + } + consumer.close(); + + for (int i=0;i enumeration = browser.getEnumeration(); + + for (int i=0; i 0); + + assertEquals("Queue size", outbound.length, proxy.getQueueSize()); + assertEquals("Queue size", outbound.length, compdatalist.length); + assertEquals("Queue size", outbound.length, table.size()); + + + LOG.info("Send another 10"); + for (int i=0;i 0); + + assertEquals("Queue size", outbound.length*2, proxy.getQueueSize()); + assertEquals("Queue size", outbound.length*2, compdatalist.length); + assertEquals("Queue size", outbound.length * 2, table.size()); + + consumer = session.createConsumer(destination); + for (int i=0; i enumeration = browser.getEnumeration(); + + // browse the first message + assertTrue("should have received the first message", enumeration.hasMoreElements()); + assertEquals(outbound[0], enumeration.nextElement()); + + // Receive the first message. + assertEquals(outbound[0], consumer.receive(1000)); + consumer.close(); + browser.close(); + producer.close(); + } + + public void testLargeNumberOfMessages() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + connection.start(); + + MessageProducer producer = session.createProducer(destination); + + int numberOfMessages = 4096; + + for (int i = 0; i < numberOfMessages; i++) { + producer.send(session.createTextMessage("Message: " + i)); + } + + QueueBrowser browser = session.createBrowser(destination); + Enumeration enumeration = browser.getEnumeration(); + + assertTrue(enumeration.hasMoreElements()); + + int numberBrowsed = 0; + + while (enumeration.hasMoreElements()) { + Message browsed = (Message) enumeration.nextElement(); + + if (LOG.isDebugEnabled()) { + LOG.debug("Browsed Message [{}]", browsed.getJMSMessageID()); + } + + numberBrowsed++; + } + + System.out.println("Number browsed: " + numberBrowsed); + assertEquals(numberOfMessages, numberBrowsed); + browser.close(); + producer.close(); + } + + public void testQueueBrowserWith2Consumers() throws Exception { + final int numMessages = 1000; + connection.setAlwaysSyncSend(false); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + ActiveMQQueue destinationPrefetch10 = new ActiveMQQueue("TEST?jms.prefetchSize=10"); + ActiveMQQueue destinationPrefetch1 = new ActiveMQQueue("TEST?jms.prefetchsize=1"); + connection.start(); + + ActiveMQConnection connection2 = (ActiveMQConnection)factory.createConnection(userName, password); + connection2.start(); + connections.add(connection2); + Session session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(destination); + MessageConsumer consumer = session.createConsumer(destinationPrefetch10); + + // lets consume any outstanding messages from previous test runs + while (consumer.receive(1000) != null) { + } + + for (int i=0; i browserView = browser.getEnumeration(); + + List messages = new ArrayList(); + for (int i = 0; i < numMessages; i++) { + Message m1 = consumer.receive(5000); + assertNotNull("m1 is null for index: " + i, m1); + messages.add(m1); + } + + int i = 0; + for (; i < numMessages && browserView.hasMoreElements(); i++) { + Message m1 = messages.get(i); + Message m2 = browserView.nextElement(); + assertNotNull("m2 is null for index: " + i, m2); + assertEquals(m1.getJMSMessageID(), m2.getJMSMessageID()); + } + + // currently browse max page size is ignored for a queue browser consumer + // only guarantee is a page size - but a snapshot of pagedinpending is + // used so it is most likely more + assertTrue("got at least our expected minimum in the browser: ", i > BaseDestination.MAX_PAGE_SIZE); + + assertFalse("nothing left in the browser", browserView.hasMoreElements()); + assertNull("consumer finished", consumer.receiveNoWait()); + } + + public void testBrowseClose() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + + connection.start(); + + TextMessage[] outbound = new TextMessage[]{session.createTextMessage("First Message"), + session.createTextMessage("Second Message"), + session.createTextMessage("Third Message")}; + + // create consumer + MessageConsumer consumer = session.createConsumer(destination); + // lets consume any outstanding messages from previous test runs + while (consumer.receive(1000) != null) { + } + + MessageProducer producer = session.createProducer(destination); + producer.send(outbound[0]); + producer.send(outbound[1]); + producer.send(outbound[2]); + + // create browser first + QueueBrowser browser = session.createBrowser(destination); + Enumeration enumeration = browser.getEnumeration(); + + // browse some messages + assertEquals(outbound[0], enumeration.nextElement()); + assertEquals(outbound[1], enumeration.nextElement()); + //assertEquals(outbound[2], (Message) enumeration.nextElement()); + + browser.close(); + + // Receive the first message. + TextMessage msg = (TextMessage)consumer.receive(1000); + assertEquals("Expected " + outbound[0].getText() + " but received " + msg.getText(), outbound[0], msg); + msg = (TextMessage)consumer.receive(1000); + assertEquals("Expected " + outbound[1].getText() + " but received " + msg.getText(), outbound[1], msg); + msg = (TextMessage)consumer.receive(1000); + assertEquals("Expected " + outbound[2].getText() + " but received " + msg.getText(), outbound[2], msg); + + consumer.close(); + producer.close(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService brokerService = super.createBroker(); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setUseCache(isUseCache); + policyEntry.setMaxBrowsePageSize(4096); + policyMap.setDefaultEntry(policyEntry); + brokerService.setDestinationPolicy(policyMap); + return brokerService; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueCompositeSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueCompositeSendReceiveTest.java new file mode 100644 index 0000000000..f381ec01f9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueCompositeSendReceiveTest.java @@ -0,0 +1,119 @@ +/** + * 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; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Topic; + +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.test.JmsTopicSendReceiveTest; +import org.apache.activemq.util.Wait; + + +/** + * + */ +public class JmsQueueCompositeSendReceiveTest extends JmsTopicSendReceiveTest { + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(JmsQueueCompositeSendReceiveTest.class); + + /** + * Sets a test to have a queue destination and non-persistent delivery mode. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + topic = false; + deliveryMode = DeliveryMode.NON_PERSISTENT; + super.setUp(); + } + + /** + * Returns the consumer subject. + * + * @return String - consumer subject + * @see org.apache.activemq.test.TestSupport#getConsumerSubject() + */ + protected String getConsumerSubject() { + return "FOO.BAR.HUMBUG"; + } + + /** + * Returns the producer subject. + * + * @return String - producer subject + * @see org.apache.activemq.test.TestSupport#getProducerSubject() + */ + protected String getProducerSubject() { + return "FOO.BAR.HUMBUG,FOO.BAR.HUMBUG2"; + } + + /** + * Test if all the messages sent are being received. + * + * @throws Exception + */ + public void testSendReceive() throws Exception { + super.testSendReceive(); + messages.clear(); + Destination consumerDestination = consumeSession.createQueue("FOO.BAR.HUMBUG2"); + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + consumerDestination.getClass()); + MessageConsumer consumer = null; + if (durable) { + LOG.info("Creating durable consumer"); + consumer = consumeSession.createDurableSubscriber((Topic) consumerDestination, getName()); + } else { + consumer = consumeSession.createConsumer(consumerDestination); + } + consumer.setMessageListener(this); + + assertMessagesAreReceived(); + LOG.info("" + data.length + " messages(s) received, closing down connections"); + } + + public void testDuplicate() throws Exception { + ActiveMQDestination queue = (ActiveMQDestination)session.createQueue("TEST,TEST"); + for (int i = 0; i < data.length; i++) { + Message message = createMessage(i); + configureMessage(message); + if (verbose) { + LOG.info("About to send a message: " + message + " with text: " + data[i]); + } + producer.send(queue, message); + } + + Thread.sleep(200); // wait for messages to be queued + + BrokerService broker = BrokerRegistry.getInstance().lookup("localhost"); + final Queue dest = (Queue)((RegionBroker)broker.getRegionBroker()).getQueueRegion().getDestinationMap().get(new ActiveMQQueue("TEST")); + assertTrue("all messages were received", Wait.waitFor(new Wait.Condition(){ + public boolean isSatisified() throws Exception { + return data.length == dest.getDestinationStatistics().getMessages().getCount(); + }})); + + dest.purge(); + assertEquals(0, dest.getDestinationStatistics().getMessages().getCount()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueRequestReplyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueRequestReplyTest.java new file mode 100644 index 0000000000..9282c0ce01 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueRequestReplyTest.java @@ -0,0 +1,33 @@ +/** + * 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; + +/** + * + */ +public class JmsQueueRequestReplyTest extends JmsTopicRequestReplyTest { + + /** + * Set up the test with a queue. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSelectorTest.java new file mode 100644 index 0000000000..449edda5a5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSelectorTest.java @@ -0,0 +1,28 @@ +/** + * 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; + +/** + * + */ +public class JmsQueueSelectorTest extends JmsTopicSelectorTest { + public void setUp() throws Exception { + topic = false; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTest.java new file mode 100644 index 0000000000..73e3e2474f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTest.java @@ -0,0 +1,35 @@ +/** + * 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; + +import org.apache.activemq.test.JmsTopicSendReceiveTest; + +/** + * + */ +public class JmsQueueSendReceiveTest extends JmsTopicSendReceiveTest { + + /** + * Set up the test with a queue. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTwoConnectionsStartBeforeBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTwoConnectionsStartBeforeBrokerTest.java new file mode 100644 index 0000000000..367aaeb231 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTwoConnectionsStartBeforeBrokerTest.java @@ -0,0 +1,86 @@ +/** + * 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; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsQueueSendReceiveTwoConnectionsStartBeforeBrokerTest extends JmsQueueSendReceiveTwoConnectionsTest { + private static final Logger LOG = LoggerFactory.getLogger(JmsQueueSendReceiveTwoConnectionsStartBeforeBrokerTest.class); + + private Queue errors = new ConcurrentLinkedQueue(); + private int delayBeforeStartingBroker = 1000; + private BrokerService broker; + + public void startBroker() { + // Initialize the broker + LOG.info("Lets wait: " + delayBeforeStartingBroker + " millis before creating the broker"); + try { + Thread.sleep(delayBeforeStartingBroker); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + LOG.info("Now starting the broker"); + try { + broker = new BrokerService(); + broker.setPersistent(false); + broker.addConnector("tcp://localhost:61616"); + broker.start(); + } catch (Exception e) { + LOG.info("Caught: " + e); + errors.add(e); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("failover:(tcp://localhost:61616)?maxReconnectAttempts=10&useExponentialBackOff=false&initialReconnectDelay=200"); + } + + protected void setUp() throws Exception { + setAutoFail(true); + // now lets asynchronously start a broker + Thread thread = new Thread() { + public void run() { + startBroker(); + } + }; + thread.start(); + + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + + if (broker != null) { + broker.stop(); + } + if (!errors.isEmpty()) { + Exception e = errors.remove(); + throw e; + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTwoConnectionsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTwoConnectionsTest.java new file mode 100644 index 0000000000..f29cc09e6c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveTwoConnectionsTest.java @@ -0,0 +1,36 @@ +/** + * 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; + +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; + +/** + * + */ +public class JmsQueueSendReceiveTwoConnectionsTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + + /** + * Set up the test with a queue and using two connections. + * + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveUsingTwoSessionsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveUsingTwoSessionsTest.java new file mode 100644 index 0000000000..cb793d0c3a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueSendReceiveUsingTwoSessionsTest.java @@ -0,0 +1,33 @@ +/** + * 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; + +/** + * + */ +public class JmsQueueSendReceiveUsingTwoSessionsTest extends JmsQueueSendReceiveTest { + + /** + * Set up the test using two sessions. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + useSeparateSession = true; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueTopicCompositeSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueTopicCompositeSendReceiveTest.java new file mode 100644 index 0000000000..d92696e8db --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueTopicCompositeSendReceiveTest.java @@ -0,0 +1,88 @@ +/** + * 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; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Topic; + +import org.apache.activemq.test.JmsTopicSendReceiveTest; + + +/** + * + */ +public class JmsQueueTopicCompositeSendReceiveTest extends JmsTopicSendReceiveTest { + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(JmsQueueTopicCompositeSendReceiveTest.class); + Destination consumerDestination2; + MessageConsumer consumer2; + + /** + * Sets a test to have a queue destination and non-persistent delivery mode. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + deliveryMode = DeliveryMode.NON_PERSISTENT; + topic = false; + super.setUp(); + consumerDestination2 = consumeSession.createTopic("FOO.BAR.HUMBUG2"); + LOG.info("Created consumer destination: " + consumerDestination2 + " of type: " + consumerDestination2.getClass()); + if (durable) { + LOG.info("Creating durable consumer"); + consumer2 = consumeSession.createDurableSubscriber((Topic) consumerDestination2, getName()); + } else { + consumer2 = consumeSession.createConsumer(consumerDestination2); + } + + } + + /** + * Returns the consumer subject. + * + * @return String - consumer subject + * @see org.apache.activemq.test.TestSupport#getConsumerSubject() + */ + protected String getConsumerSubject() { + return "FOO.BAR.HUMBUG"; + } + + /** + * Returns the producer subject. + * + * @return String - producer subject + * @see org.apache.activemq.test.TestSupport#getProducerSubject() + */ + protected String getProducerSubject() { + return "queue://FOO.BAR.HUMBUG,topic://FOO.BAR.HUMBUG2"; + } + + /** + * Test if all the messages sent are being received. + * + * @throws Exception + */ + public void testSendReceive() throws Exception { + super.testSendReceive(); + messages.clear(); + consumer2.setMessageListener(this); + assertMessagesAreReceived(); + LOG.info("" + data.length + " messages(s) received, closing down connections"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueWildcardSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueWildcardSendReceiveTest.java new file mode 100644 index 0000000000..b689664ac0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsQueueWildcardSendReceiveTest.java @@ -0,0 +1,174 @@ +/** + * 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; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.test.JmsTopicSendReceiveTest; + +/** + * + */ +public class JmsQueueWildcardSendReceiveTest extends JmsTopicSendReceiveTest { + + private String destination1String = "TEST.ONE.ONE"; + private String destination2String = "TEST.ONE.ONE.ONE"; + private String destination3String = "TEST.ONE.TWO"; + private String destination4String = "TEST.TWO.ONE"; + + /** + * Sets a test to have a queue destination and non-persistent delivery mode. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + topic = false; + deliveryMode = DeliveryMode.NON_PERSISTENT; + super.setUp(); + } + + /** + * Returns the consumer subject. + * + * @return String - consumer subject + * @see org.apache.activemq.test.TestSupport#getConsumerSubject() + */ + protected String getConsumerSubject() { + return "FOO.>"; + } + + /** + * Returns the producer subject. + * + * @return String - producer subject + * @see org.apache.activemq.test.TestSupport#getProducerSubject() + */ + protected String getProducerSubject() { + return "FOO.BAR.HUMBUG"; + } + + public void testReceiveWildcardQueueEndAsterisk() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createQueue(destination1String); + ActiveMQDestination destination3 = (ActiveMQDestination)session.createQueue(destination3String); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + sendMessage(session, destination1, destination1String); + sendMessage(session, destination3, destination3String); + ActiveMQDestination destination6 = (ActiveMQDestination)session.createQueue("TEST.ONE.*"); + consumer = session.createConsumer(destination6); + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + assertNull(consumer.receiveNoWait()); + } + + public void testReceiveWildcardQueueEndGreaterThan() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createQueue(destination1String); + ActiveMQDestination destination2 = (ActiveMQDestination)session.createQueue(destination2String); + ActiveMQDestination destination3 = (ActiveMQDestination)session.createQueue(destination3String); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + sendMessage(session, destination1, destination1String); + sendMessage(session, destination2, destination2String); + sendMessage(session, destination3, destination3String); + ActiveMQDestination destination7 = (ActiveMQDestination)session.createQueue("TEST.ONE.>"); + consumer = session.createConsumer(destination7); + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination2String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + if (!(text.equals(destination1String) || text.equals(destination2String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + if (!(text.equals(destination1String) || text.equals(destination2String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + assertNull(consumer.receiveNoWait()); + } + + public void testReceiveWildcardQueueMidAsterisk() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createQueue(destination1String); + ActiveMQDestination destination4 = (ActiveMQDestination)session.createQueue(destination4String); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + sendMessage(session, destination1, destination1String); + sendMessage(session, destination4, destination4String); + ActiveMQDestination destination8 = (ActiveMQDestination)session.createQueue("TEST.*.ONE"); + consumer = session.createConsumer(destination8); + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination4String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination4String))) { + fail("unexpected message:" + text); + } + assertNull(consumer.receiveNoWait()); + + } + + private void sendMessage(Session session, Destination destination, String text) throws JMSException { + MessageProducer producer = session.createProducer(destination); + producer.send(session.createTextMessage(text)); + producer.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsRedeliveredTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsRedeliveredTest.java new file mode 100644 index 0000000000..e5d90d681e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsRedeliveredTest.java @@ -0,0 +1,562 @@ +/** + * 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; + +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.activemq.transport.vm.VMTransport; +import org.apache.activemq.util.Wait; + +/** + * + */ +public class JmsRedeliveredTest extends TestCase { + + private Connection connection; + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + } + + /** + * Creates a connection. + * + * @return connection + * @throws Exception + */ + protected Connection createConnection() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + "vm://localhost?broker.persistent=false"); + return factory.createConnection(); + } + + /** + * Tests if a message unacknowledged message gets to be resent when the + * session is closed and then a new consumer session is created. + * + */ + public void testQueueSessionCloseMarksMessageRedelivered() throws JMSException { + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + MessageProducer producer = createProducer(session, queue); + producer.send(createTextMessage(session)); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + // Don't ack the message. + + // Reset the session. This should cause the Unacked message to be + // redelivered. + session.close(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + msg.acknowledge(); + + session.close(); + } + + + + public void testQueueSessionCloseMarksUnAckedMessageRedelivered() throws JMSException { + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + MessageProducer producer = createProducer(session, queue); + producer.send(createTextMessage(session, "1")); + producer.send(createTextMessage(session, "2")); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + assertEquals("1", ((TextMessage)msg).getText()); + msg.acknowledge(); + + // Don't ack the message. + msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + assertEquals("2", ((TextMessage)msg).getText()); + + // Reset the session. This should cause the Unacked message to be + // redelivered. + session.close(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createConsumer(queue); + msg = consumer.receive(2000); + assertNotNull(msg); + assertEquals("2", ((TextMessage)msg).getText()); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + msg.acknowledge(); + + session.close(); + } + + /** + * Tests session recovery and that the redelivered message is marked as + * such. Session uses client acknowledgement, the destination is a queue. + * + * @throws JMSException + */ + public void testQueueRecoverMarksMessageRedelivered() throws JMSException { + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + MessageProducer producer = createProducer(session, queue); + producer.send(createTextMessage(session)); + + // Consume the message... + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + // Don't ack the message. + + // Reset the session. This should cause the Unacked message to be + // redelivered. + session.recover(); + + // Attempt to Consume the message... + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + msg.acknowledge(); + + session.close(); + } + + /** + * Tests rollback message to be marked as redelivered. Session uses client + * acknowledgement and the destination is a queue. + * + * @throws JMSException + */ + public void testQueueRollbackMarksMessageRedelivered() throws JMSException { + connection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + MessageProducer producer = createProducer(session, queue); + producer.send(createTextMessage(session)); + session.commit(); + + // Get the message... Should not be redelivered. + MessageConsumer consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + + // Rollback.. should cause redelivery. + session.rollback(); + + // Attempt to Consume the message... + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + + session.commit(); + session.close(); + } + + /** + * Tests if the message gets to be re-delivered when the session closes and + * that the re-delivered message is marked as such. Session uses client + * acknowledgment, the destination is a topic and the consumer is a durable + * subscriber. + * + * @throws JMSException + */ + public void testDurableTopicSessionCloseMarksMessageRedelivered() throws JMSException { + connection.setClientID(getName()); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1"); + + // This case only works with persistent messages since transient + // messages + // are dropped when the consumer goes offline. + MessageProducer producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.send(createTextMessage(session)); + + // Consume the message... + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be re-delivered.", msg.getJMSRedelivered()); + // Don't ack the message. + + // Reset the session. This should cause the Unacked message to be + // re-delivered. + session.close(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Attempt to Consume the message... + consumer = session.createDurableSubscriber(topic, "sub1"); + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + msg.acknowledge(); + + session.close(); + } + + /** + * Tests session recovery and that the redelivered message is marked as + * such. Session uses client acknowledgement, the destination is a topic and + * the consumer is a durable suscriber. + * + * @throws JMSException + */ + public void testDurableTopicRecoverMarksMessageRedelivered() throws JMSException { + connection.setClientID(getName()); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1"); + + MessageProducer producer = createProducer(session, topic); + producer.send(createTextMessage(session)); + + // Consume the message... + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + // Don't ack the message. + + // Reset the session. This should cause the Unacked message to be + // redelivered. + session.recover(); + + // Attempt to Consume the message... + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + msg.acknowledge(); + + session.close(); + } + + /** + * Tests rollback message to be marked as redelivered. Session uses client + * acknowledgement and the destination is a topic. + * + * @throws JMSException + */ + public void testDurableTopicRollbackMarksMessageRedelivered() throws JMSException { + connection.setClientID(getName()); + connection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1"); + + MessageProducer producer = createProducer(session, topic); + producer.send(createTextMessage(session)); + session.commit(); + + // Get the message... Should not be redelivered. + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + + // Rollback.. should cause redelivery. + session.rollback(); + + // Attempt to Consume the message... + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + + session.commit(); + session.close(); + } + + /** + * + * + * @throws JMSException + */ + public void testTopicRecoverMarksMessageRedelivered() throws JMSException { + + connection.setClientID(getName()); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createConsumer(topic); + + MessageProducer producer = createProducer(session, topic); + producer.send(createTextMessage(session)); + + // Consume the message... + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + // Don't ack the message. + + // Reset the session. This should cause the Unacked message to be + // redelivered. + session.recover(); + + // Attempt to Consume the message... + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + msg.acknowledge(); + + session.close(); + } + + /** + * Tests rollback message to be marked as redelivered. Session uses client + * acknowledgement and the destination is a topic. + * + * @throws JMSException + */ + public void testTopicRollbackMarksMessageRedelivered() throws JMSException { + connection.setClientID(getName()); + connection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createConsumer(topic); + + MessageProducer producer = createProducer(session, topic); + producer.send(createTextMessage(session)); + session.commit(); + + // Get the message... Should not be redelivered. + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + + // Rollback.. should cause redelivery. + session.rollback(); + + // Attempt to Consume the message... + msg = consumer.receive(2000); + assertNotNull(msg); + assertTrue("Message should be redelivered.", msg.getJMSRedelivered()); + + session.commit(); + session.close(); + } + + public void testNoReceiveConsumerDisconnectDoesNotIncrementRedelivery() throws Exception { + connection.setClientID(getName()); + connection.start(); + + Connection keepBrokerAliveConnection = createConnection(); + keepBrokerAliveConnection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + final MessageConsumer consumer = session.createConsumer(queue); + + MessageProducer producer = createProducer(session, queue); + producer.send(createTextMessage(session)); + session.commit(); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return ((ActiveMQMessageConsumer)consumer).getMessageSize() == 1; + } + }); + + // whack the connection - like a rebalance or tcp drop + ((ActiveMQConnection)connection).getTransport().narrow(VMTransport.class).stop(); + + session = keepBrokerAliveConnection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer messageConsumer = session.createConsumer(queue); + Message msg = messageConsumer.receive(1000); + assertNotNull(msg); + msg.acknowledge(); + + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + session.close(); + keepBrokerAliveConnection.close(); + } + + public void testNoReceiveConsumerDoesNotIncrementRedelivery() throws Exception { + connection.setClientID(getName()); + connection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + MessageConsumer consumer = session.createConsumer(queue); + + MessageProducer producer = createProducer(session, queue); + producer.send(createTextMessage(session)); + session.commit(); + + TimeUnit.SECONDS.sleep(1); + consumer.close(); + + consumer = session.createConsumer(queue); + Message msg = consumer.receive(1000); + assertNotNull(msg); + + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + session.close(); + } + + public void testNoReceiveDurableConsumerDoesNotIncrementRedelivery() throws Exception { + connection.setClientID(getName()); + connection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createDurableSubscriber(topic, "sub"); + + MessageProducer producer = createProducer(session, topic); + producer.send(createTextMessage(session)); + session.commit(); + + TimeUnit.SECONDS.sleep(1); + consumer.close(); + + consumer = session.createDurableSubscriber(topic, "sub"); + Message msg = consumer.receive(1000); + assertNotNull(msg); + + assertFalse("Message should not be redelivered.", msg.getJMSRedelivered()); + session.close(); + } + + /** + * Creates a text message. + * + * @param session + * @return TextMessage. + * @throws JMSException + */ + private TextMessage createTextMessage(Session session) throws JMSException { + return createTextMessage(session, "Hello"); + } + + private TextMessage createTextMessage(Session session, String txt) throws JMSException { + return session.createTextMessage(txt); + } + + /** + * Creates a producer. + * + * @param session + * @param queue - destination. + * @return MessageProducer + * @throws JMSException + */ + private MessageProducer createProducer(Session session, Destination queue) throws JMSException { + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(getDeliveryMode()); + return producer; + } + + /** + * Returns delivery mode. + * + * @return int - persistent delivery mode. + */ + protected int getDeliveryMode() { + return DeliveryMode.PERSISTENT; + } + + /** + * Run the JmsRedeliverTest with the delivery mode set as persistent. + */ + public static final class PersistentCase extends JmsRedeliveredTest { + + /** + * Returns delivery mode. + * + * @return int - persistent delivery mode. + */ + protected int getDeliveryMode() { + return DeliveryMode.PERSISTENT; + } + } + + /** + * Run the JmsRedeliverTest with the delivery mode set as non-persistent. + */ + public static final class TransientCase extends JmsRedeliveredTest { + + /** + * Returns delivery mode. + * + * @return int - non-persistent delivery mode. + */ + protected int getDeliveryMode() { + return DeliveryMode.NON_PERSISTENT; + } + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTestSuite(PersistentCase.class); + suite.addTestSuite(TransientCase.class); + return suite; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsRollbackRedeliveryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsRollbackRedeliveryTest.java new file mode 100644 index 0000000000..91e29c053d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsRollbackRedeliveryTest.java @@ -0,0 +1,358 @@ +/** + * 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; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.*; + +public class JmsRollbackRedeliveryTest { + @Rule + public TestName testName = new TestName(); + + protected static final Logger LOG = LoggerFactory.getLogger(JmsRollbackRedeliveryTest.class); + final int nbMessages = 10; + final String destinationName = "Destination"; + final String brokerUrl = "vm://localhost?create=false"; + boolean consumerClose = true; + boolean rollback = true; + BrokerService broker; + + @Before + public void setUp() throws Exception { + LOG.debug("Starting " + testName.getMethodName()); + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + LOG.debug("Finishing " + testName.getMethodName()); + Thread.sleep(100); + } + + @Test + public void testRedelivery() throws Exception { + doTestRedelivery(brokerUrl, false); + } + + @Test + public void testRedeliveryWithInterleavedProducer() throws Exception { + doTestRedelivery(brokerUrl, true); + } + + + @Test + public void testRedeliveryWithPrefetch0() throws Exception { + doTestRedelivery(brokerUrl + "?jms.prefetchPolicy.queuePrefetch=0", true); + } + + @Test + public void testRedeliveryWithPrefetch1() throws Exception { + doTestRedelivery(brokerUrl + "?jms.prefetchPolicy.queuePrefetch=1", true); + } + + public void doTestRedelivery(String brokerUrl, boolean interleaveProducer) throws Exception { + LOG.debug("entering doTestRedelivery interleaveProducer is " + interleaveProducer); + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrl); + + Connection connection = connectionFactory.createConnection(); + connection.start(); + + if (interleaveProducer) { + populateDestinationWithInterleavedProducer(nbMessages, destinationName, connection); + } else { + populateDestination(nbMessages, destinationName, connection); + } + + // Consume messages and rollback transactions + { + AtomicInteger received = new AtomicInteger(); + Map rolledback = new ConcurrentHashMap(); + while (received.get() < nbMessages) { + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = (TextMessage) consumer.receive(6000000); + if (msg != null) { + if (msg != null && rolledback.put(msg.getText(), Boolean.TRUE) != null) { + LOG.info("Received message " + msg.getText() + " (" + received.getAndIncrement() + ")" + msg.getJMSMessageID()); + assertTrue(msg.getJMSRedelivered()); + assertEquals(2, msg.getLongProperty("JMSXDeliveryCount")); + session.commit(); + } else { + LOG.info("Rollback message " + msg.getText() + " id: " + msg.getJMSMessageID()); + assertFalse("should not have redelivery flag set, id: " + msg.getJMSMessageID(), msg.getJMSRedelivered()); + session.rollback(); + } + } + consumer.close(); + session.close(); + } + } + } + + @Test + public void testRedeliveryOnSingleConsumer() throws Exception { + + ConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(brokerUrl); + Connection connection = connectionFactory.createConnection(); + connection.start(); + + populateDestinationWithInterleavedProducer(nbMessages, destinationName, connection); + + // Consume messages and rollback transactions + { + AtomicInteger received = new AtomicInteger(); + Map rolledback = new ConcurrentHashMap(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageConsumer consumer = session.createConsumer(destination); + while (received.get() < nbMessages) { + TextMessage msg = (TextMessage) consumer.receive(6000000); + if (msg != null) { + if (msg != null && rolledback.put(msg.getText(), Boolean.TRUE) != null) { + LOG.info("Received message " + msg.getText() + " (" + received.getAndIncrement() + ")" + msg.getJMSMessageID()); + assertTrue(msg.getJMSRedelivered()); + session.commit(); + } else { + LOG.info("Rollback message " + msg.getText() + " id: " + msg.getJMSMessageID()); + session.rollback(); + } + } + } + consumer.close(); + session.close(); + } + } + + + @Test + public void testRedeliveryOnSingleSession() throws Exception { + + ConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(brokerUrl); + Connection connection = connectionFactory.createConnection(); + connection.start(); + + populateDestination(nbMessages, destinationName, connection); + + // Consume messages and rollback transactions + { + AtomicInteger received = new AtomicInteger(); + Map rolledback = new ConcurrentHashMap(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + while (received.get() < nbMessages) { + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = (TextMessage) consumer.receive(6000000); + if (msg != null) { + if (msg != null && rolledback.put(msg.getText(), Boolean.TRUE) != null) { + LOG.info("Received message " + msg.getText() + " (" + received.getAndIncrement() + ")" + msg.getJMSMessageID()); + assertTrue(msg.getJMSRedelivered()); + session.commit(); + } else { + LOG.info("Rollback message " + msg.getText() + " id: " + msg.getJMSMessageID()); + session.rollback(); + } + } + consumer.close(); + } + session.close(); + } + } + + // AMQ-1593 + @Test + public void testValidateRedeliveryCountOnRollback() throws Exception { + + final int numMessages = 1; + ConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(brokerUrl); + Connection connection = connectionFactory.createConnection(); + connection.start(); + + populateDestination(numMessages, destinationName, connection); + + { + AtomicInteger received = new AtomicInteger(); + final int maxRetries = new RedeliveryPolicy().getMaximumRedeliveries(); + while (received.get() < maxRetries) { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(destinationName); + + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = (TextMessage) consumer.receive(1000); + if (msg != null) { + LOG.info("Received message " + msg.getText() + " (" + received.getAndIncrement() + ")" + msg.getJMSMessageID()); + assertEquals("redelivery property matches deliveries", received.get(), msg.getLongProperty("JMSXDeliveryCount")); + session.rollback(); + } + session.close(); + } + consumeMessage(connection, maxRetries + 1); + } + } + + // AMQ-1593 + @Test + public void testValidateRedeliveryCountOnRollbackWithPrefetch0() throws Exception { + + final int numMessages = 1; + ConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(brokerUrl + "?jms.prefetchPolicy.queuePrefetch=0"); + Connection connection = connectionFactory.createConnection(); + connection.start(); + + populateDestination(numMessages, destinationName, connection); + + { + AtomicInteger received = new AtomicInteger(); + final int maxRetries = new RedeliveryPolicy().getMaximumRedeliveries(); + while (received.get() < maxRetries) { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(destinationName); + + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = (TextMessage) consumer.receive(1000); + if (msg != null) { + LOG.info("Received message " + msg.getText() + " (" + received.getAndIncrement() + ")" + msg.getJMSMessageID()); + assertEquals("redelivery property matches deliveries", received.get(), msg.getLongProperty("JMSXDeliveryCount")); + session.rollback(); + } + session.close(); + } + + consumeMessage(connection, maxRetries + 1); + } + } + + + private void consumeMessage(Connection connection, final int deliveryCount) + throws JMSException { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(destinationName); + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = (TextMessage) consumer.receive(1000); + assertNotNull(msg); + assertEquals("redelivery property matches deliveries", deliveryCount, msg.getLongProperty("JMSXDeliveryCount")); + session.commit(); + session.close(); + } + + @Test + public void testRedeliveryPropertyWithNoRollback() throws Exception { + final int numMessages = 1; + ConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(brokerUrl); + Connection connection = connectionFactory.createConnection(); + connection.start(); + + populateDestination(numMessages, destinationName, connection); + connection.close(); + + { + AtomicInteger received = new AtomicInteger(); + final int maxRetries = new RedeliveryPolicy().getMaximumRedeliveries(); + while (received.get() < maxRetries) { + connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(destinationName); + + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = (TextMessage) consumer.receive(2000); + if (msg != null) { + LOG.info("Received message " + msg.getText() + " (" + received.getAndIncrement() + ")" + msg.getJMSMessageID()); + assertEquals("redelivery property matches deliveries", received.get(), msg.getLongProperty("JMSXDeliveryCount")); + } + session.close(); + connection.close(); + } + connection = connectionFactory.createConnection(); + connection.start(); + consumeMessage(connection, maxRetries + 1); + } + } + + private void populateDestination(final int nbMessages, + final String destinationName, Connection connection) + throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageProducer producer = session.createProducer(destination); + for (int i = 1; i <= nbMessages; i++) { + producer.send(session.createTextMessage("")); + } + producer.close(); + session.close(); + } + + + private void populateDestinationWithInterleavedProducer(final int nbMessages, + final String destinationName, Connection connection) + throws JMSException { + Session session1 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination1 = session1.createQueue(destinationName); + MessageProducer producer1 = session1.createProducer(destination1); + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination2 = session2.createQueue(destinationName); + MessageProducer producer2 = session2.createProducer(destination2); + + for (int i = 1; i <= nbMessages; i++) { + if (i%2 == 0) { + producer1.send(session1.createTextMessage("")); + } else { + producer2.send(session2.createTextMessage("")); + } + } + producer1.close(); + session1.close(); + producer2.close(); + session2.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendReceiveTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendReceiveTestSupport.java new file mode 100644 index 0000000000..d852f54946 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendReceiveTestSupport.java @@ -0,0 +1,237 @@ +/** + * 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; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsSendReceiveTestSupport extends TestSupport implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(JmsSendReceiveTestSupport.class); + + protected int messageCount = 100; + protected String[] data; + protected Session session; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected Destination consumerDestination; + protected Destination producerDestination; + protected List messages = createConcurrentList(); + protected boolean topic = true; + protected boolean durable; + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected final Object lock = new Object(); + protected boolean verbose; + + /* + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + String temp = System.getProperty("messageCount"); + + if (temp != null) { + int i = Integer.parseInt(temp); + if (i > 0) { + messageCount = i; + } + } + + LOG.info("Message count for test case is: " + messageCount); + data = new String[messageCount]; + + for (int i = 0; i < messageCount; i++) { + data[i] = "Text for message: " + i + " at " + new Date(); + } + } + + /** + * Sends and consumes the messages. + * + * @throws Exception + */ + public void testSendReceive() throws Exception { + messages.clear(); + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(data[i]); + message.setStringProperty("stringProperty", data[i]); + message.setIntProperty("intProperty", i); + + if (verbose) { + if (LOG.isDebugEnabled()) { + LOG.debug("About to send a message: " + message + " with text: " + data[i]); + } + } + + sendToProducer(producer, producerDestination, message); + messageSent(); + } + + assertMessagesAreReceived(); + LOG.info("" + data.length + " messages(s) received, closing down connections"); + } + + /** + * Sends a message to a destination using the supplied producer + * @param producer + * @param producerDestination + * @param message + * @throws JMSException + */ + protected void sendToProducer(MessageProducer producer, + Destination producerDestination, Message message) throws JMSException { + producer.send(producerDestination, message); + } + + /** + * Asserts messages are received. + * + * @throws JMSException + */ + protected void assertMessagesAreReceived() throws JMSException { + waitForMessagesToBeDelivered(); + assertMessagesReceivedAreValid(messages); + } + + /** + * Tests if the messages received are valid. + * + * @param receivedMessages - list of received messages. + * @throws JMSException + */ + protected void assertMessagesReceivedAreValid(List receivedMessages) throws JMSException { + List copyOfMessages = Arrays.asList(receivedMessages.toArray()); + int counter = 0; + + if (data.length != copyOfMessages.size()) { + for (Iterator iter = copyOfMessages.iterator(); iter.hasNext();) { + TextMessage message = (TextMessage)iter.next(); + if (LOG.isInfoEnabled()) { + LOG.info("<== " + counter++ + " = " + message.getText()); + } + } + } + + assertEquals("Not enough messages received", data.length, receivedMessages.size()); + + for (int i = 0; i < data.length; i++) { + TextMessage received = (TextMessage)receivedMessages.get(i); + String text = received.getText(); + String stringProperty = received.getStringProperty("stringProperty"); + int intProperty = received.getIntProperty("intProperty"); + + if (verbose) { + if (LOG.isDebugEnabled()) { + LOG.info("Received Text: " + text); + } + } + + assertEquals("Message: " + i, data[i], text); + assertEquals(data[i], stringProperty); + assertEquals(i, intProperty); + } + } + + /** + * Waits for messages to be delivered. + */ + protected void waitForMessagesToBeDelivered() { + long maxWaitTime = 60000; + long waitTime = maxWaitTime; + long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); + + synchronized (lock) { + while (messages.size() < data.length && waitTime >= 0) { + try { + lock.wait(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + waitTime = maxWaitTime - (System.currentTimeMillis() - start); + } + } + } + + /* + * (non-Javadoc) + * + * @see javax.jms.MessageListener#onMessage(javax.jms.Message) + */ + public synchronized void onMessage(Message message) { + consumeMessage(message, messages); + } + + /** + * Consumes messages. + * + * @param message - message to be consumed. + * @param messageList -list of consumed messages. + */ + protected void consumeMessage(Message message, List messageList) { + if (verbose) { + if (LOG.isDebugEnabled()) { + LOG.info("Received message: " + message); + } + } + + messageList.add(message); + + if (messageList.size() >= data.length) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + + /** + * Returns the ArrayList as a synchronized list. + * + * @return List + */ + protected List createConcurrentList() { + return Collections.synchronizedList(new ArrayList()); + } + + /** + * Just a hook so can insert failure tests + * + * @throws Exception + */ + protected void messageSent() throws Exception { + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendReceiveWithMessageExpirationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendReceiveWithMessageExpirationTest.java new file mode 100644 index 0000000000..391253ee70 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendReceiveWithMessageExpirationTest.java @@ -0,0 +1,310 @@ +/** + * 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; + +import java.util.Date; +import java.util.Vector; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsSendReceiveWithMessageExpirationTest extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(JmsSendReceiveWithMessageExpirationTest.class); + + protected int messageCount = 100; + protected String[] data; + protected Session session; + protected Destination consumerDestination; + protected Destination producerDestination; + protected boolean durable; + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected long timeToLive = 5000; + protected boolean verbose; + + protected Connection connection; + + protected void setUp() throws Exception { + + super.setUp(); + + data = new String[messageCount]; + + for (int i = 0; i < messageCount; i++) { + data[i] = "Text for message: " + i + " at " + new Date(); + } + + connectionFactory = createConnectionFactory(); + connection = createConnection(); + + if (durable) { + connection.setClientID(getClass().getName()); + } + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + /** + * Test consuming an expired queue. + * + * @throws Exception + */ + public void testConsumeExpiredQueue() throws Exception { + + MessageProducer producer = createProducer(timeToLive); + + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + + MessageConsumer consumer = createConsumer(); + connection.start(); + + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(data[i]); + message.setStringProperty("stringProperty", data[i]); + message.setIntProperty("intProperty", i); + + if (verbose) { + if (LOG.isDebugEnabled()) { + LOG.debug("About to send a queue message: " + message + " with text: " + data[i]); + } + } + + producer.send(producerDestination, message); + } + + // sleeps a second longer than the expiration time. + // Basically waits till queue expires. + Thread.sleep(timeToLive + 1000); + + // message should have expired. + assertNull(consumer.receive(1000)); + } + + public void testConsumeExpiredQueueAndDlq() throws Exception { + + MessageProducer producerNormal = createProducer(0); + MessageProducer producerExpire = createProducer(500); + + consumerDestination = session.createQueue("ActiveMQ.DLQ"); + MessageConsumer dlqConsumer = createConsumer(); + + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + + + Connection consumerConnection = createConnection(); + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setAll(10); + ((ActiveMQConnection)consumerConnection).setPrefetchPolicy(prefetchPolicy); + Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(consumerDestination); + consumerConnection.start(); + connection.start(); + + String msgBody = new String(new byte[20*1024]); + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(msgBody); + producerExpire.send(producerDestination, message); + } + + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(msgBody); + producerNormal.send(producerDestination, message); + } + + Vector messages = new Vector(); + Message received; + while ((received = consumer.receive(1000)) != null) { + messages.add(received); + if (messages.size() == 1) { + TimeUnit.SECONDS.sleep(1); + } + received.acknowledge(); + }; + + assertEquals("got all (normal plus one with ttl) messages", messageCount + 1, messages.size()); + + Vector dlqMessages = new Vector(); + while ((received = dlqConsumer.receive(1000)) != null) { + dlqMessages.add(received); + }; + + assertEquals("got dlq messages", data.length - 1, dlqMessages.size()); + + final DestinationStatistics view = getDestinationStatistics(BrokerRegistry.getInstance().findFirst(), ActiveMQDestination.transform(consumerDestination)); + + // wait for all to inflight to expire + assertTrue("all inflight messages expired ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return view.getInflight().getCount() == 0; + } + })); + assertEquals("Wrong inFlightCount: ", 0, view.getInflight().getCount()); + + LOG.info("Stats: received: " + messages.size() + ", messages: " + view.getMessages().getCount() + ", enqueues: " + view.getEnqueues().getCount() + ", dequeues: " + view.getDequeues().getCount() + + ", dispatched: " + view.getDispatched().getCount() + ", inflight: " + view.getInflight().getCount() + ", expired: " + view.getExpired().getCount()); + + } + + /** + * Sends and consumes the messages to a queue destination. + * + * @throws Exception + */ + public void testConsumeQueue() throws Exception { + + MessageProducer producer = createProducer(0); + + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + + MessageConsumer consumer = createConsumer(); + connection.start(); + + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(data[i]); + message.setStringProperty("stringProperty", data[i]); + message.setIntProperty("intProperty", i); + + if (verbose) { + if (LOG.isDebugEnabled()) { + LOG.debug("About to send a queue message: " + message + " with text: " + data[i]); + } + } + + producer.send(producerDestination, message); + } + + // should receive a queue since there is no expiration. + assertNotNull(consumer.receive(1000)); + } + + /** + * Test consuming an expired topic. + * + * @throws Exception + */ + public void testConsumeExpiredTopic() throws Exception { + + MessageProducer producer = createProducer(timeToLive); + + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + + MessageConsumer consumer = createConsumer(); + connection.start(); + + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(data[i]); + message.setStringProperty("stringProperty", data[i]); + message.setIntProperty("intProperty", i); + + if (verbose) { + if (LOG.isDebugEnabled()) { + LOG.debug("About to send a topic message: " + message + " with text: " + data[i]); + } + } + + producer.send(producerDestination, message); + } + + // sleeps a second longer than the expiration time. + // Basically waits till topic expires. + Thread.sleep(timeToLive + 1000); + + // message should have expired. + assertNull(consumer.receive(1000)); + } + + /** + * Sends and consumes the messages to a topic destination. + * + * @throws Exception + */ + public void testConsumeTopic() throws Exception { + + MessageProducer producer = createProducer(0); + + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + + MessageConsumer consumer = createConsumer(); + connection.start(); + + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(data[i]); + message.setStringProperty("stringProperty", data[i]); + message.setIntProperty("intProperty", i); + + if (verbose) { + if (LOG.isDebugEnabled()) { + LOG.debug("About to send a topic message: " + message + " with text: " + data[i]); + } + } + + producer.send(producerDestination, message); + } + + // should receive a topic since there is no expiration. + assertNotNull(consumer.receive(1000)); + } + + protected MessageProducer createProducer(long timeToLive) throws JMSException { + MessageProducer producer = session.createProducer(null); + producer.setDeliveryMode(deliveryMode); + producer.setTimeToLive(timeToLive); + + return producer; + } + + protected MessageConsumer createConsumer() throws JMSException { + if (durable) { + LOG.info("Creating durable consumer"); + return session.createDurableSubscriber((Topic)consumerDestination, getName()); + } + return session.createConsumer(consumerDestination); + } + + protected void tearDown() throws Exception { + LOG.info("Dumping stats..."); + LOG.info("Closing down connection"); + + session.close(); + connection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendWithAsyncCallbackTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendWithAsyncCallbackTest.java new file mode 100644 index 0000000000..cf14453668 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSendWithAsyncCallbackTest.java @@ -0,0 +1,127 @@ +/** + * 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; + +import java.util.concurrent.CountDownLatch; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.Session; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsSendWithAsyncCallbackTest extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(JmsSendWithAsyncCallbackTest.class); + + private Connection connection; + + @Override + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + public void testAsyncCallbackIsFaster() throws JMSException, InterruptedException { + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(getName()); + + // setup a consumer to drain messages.. + MessageConsumer consumer = session.createConsumer(queue); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + } + }); + + // warmup... + for (int i = 0; i < 10; i++) { + benchmarkNonCallbackRate(); + benchmarkCallbackRate(); + } + + double callbackRate = benchmarkCallbackRate(); + double nonCallbackRate = benchmarkNonCallbackRate(); + + LOG.info(String.format("AsyncCallback Send rate: %,.2f m/s", callbackRate)); + LOG.info(String.format("NonAsyncCallback Send rate: %,.2f m/s", nonCallbackRate)); + + // The async style HAS to be faster than the non-async style.. + assertTrue("async rate[" + callbackRate + "] should beat non-async rate[" + nonCallbackRate + "]", callbackRate / nonCallbackRate > 1.5); + } + + private double benchmarkNonCallbackRate() throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(getName()); + int count = 1000; + ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + long start = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + producer.send(session.createTextMessage("Hello")); + } + return 1000.0 * count / (System.currentTimeMillis() - start); + } + + private double benchmarkCallbackRate() throws JMSException, InterruptedException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(getName()); + int count = 1000; + final CountDownLatch messagesSent = new CountDownLatch(count); + ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + long start = System.currentTimeMillis(); + for (int i = 0; i < count; i++) { + producer.send(session.createTextMessage("Hello"), new AsyncCallback() { + @Override + public void onSuccess() { + messagesSent.countDown(); + } + + @Override + public void onException(JMSException exception) { + exception.printStackTrace(); + } + }); + } + messagesSent.await(); + return 1000.0 * count / (System.currentTimeMillis() - start); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSessionRecoverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSessionRecoverTest.java new file mode 100644 index 0000000000..a9e1b24fa9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsSessionRecoverTest.java @@ -0,0 +1,294 @@ +/** + * 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; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +/** + * Testcases to see if Session.recover() work. + * + * + */ +public class JmsSessionRecoverTest extends TestCase { + + private Connection connection; + private ActiveMQConnectionFactory factory; + private Destination dest; + + /** + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = factory.createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + } + + /** + * + * @throws JMSException + * @throws InterruptedException + */ + public void testQueueSynchRecover() throws JMSException, InterruptedException { + dest = new ActiveMQQueue("Queue-" + System.currentTimeMillis()); + doTestSynchRecover(); + } + + /** + * + * @throws JMSException + * @throws InterruptedException + */ + public void testQueueAsynchRecover() throws JMSException, InterruptedException { + dest = new ActiveMQQueue("Queue-" + System.currentTimeMillis()); + doTestAsynchRecover(); + } + + /** + * + * @throws JMSException + * @throws InterruptedException + */ + public void testTopicSynchRecover() throws JMSException, InterruptedException { + dest = new ActiveMQTopic("Topic-" + System.currentTimeMillis()); + doTestSynchRecover(); + } + + /** + * + * @throws JMSException + * @throws InterruptedException + */ + public void testTopicAsynchRecover() throws JMSException, InterruptedException { + dest = new ActiveMQTopic("Topic-" + System.currentTimeMillis()); + doTestAsynchRecover(); + } + + /** + * + * @throws JMSException + * @throws InterruptedException + */ + public void testQueueAsynchRecoverWithAutoAck() throws JMSException, InterruptedException { + dest = new ActiveMQQueue("Queue-" + System.currentTimeMillis()); + doTestAsynchRecoverWithAutoAck(); + } + + /** + * + * @throws JMSException + * @throws InterruptedException + */ + public void testTopicAsynchRecoverWithAutoAck() throws JMSException, InterruptedException { + dest = new ActiveMQTopic("Topic-" + System.currentTimeMillis()); + doTestAsynchRecoverWithAutoAck(); + } + + /** + * Test to make sure that a Sync recover works. + * + * @throws JMSException + */ + public void doTestSynchRecover() throws JMSException { + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(dest); + connection.start(); + + MessageProducer producer = session.createProducer(dest); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("First")); + producer.send(session.createTextMessage("Second")); + + TextMessage message = (TextMessage)consumer.receive(1000); + assertEquals("First", message.getText()); + assertFalse(message.getJMSRedelivered()); + message.acknowledge(); + + message = (TextMessage)consumer.receive(1000); + assertEquals("Second", message.getText()); + assertFalse(message.getJMSRedelivered()); + + session.recover(); + + message = (TextMessage)consumer.receive(2000); + assertEquals("Second", message.getText()); + assertTrue(message.getJMSRedelivered()); + + message.acknowledge(); + } + + /** + * Test to make sure that a Async recover works. + * + * @throws JMSException + * @throws InterruptedException + */ + public void doTestAsynchRecover() throws JMSException, InterruptedException { + + final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final String errorMessage[] = new String[] {null}; + final CountDownLatch doneCountDownLatch = new CountDownLatch(1); + + MessageConsumer consumer = session.createConsumer(dest); + + MessageProducer producer = session.createProducer(dest); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("First")); + producer.send(session.createTextMessage("Second")); + + consumer.setMessageListener(new MessageListener() { + int counter; + + public void onMessage(Message msg) { + counter++; + try { + TextMessage message = (TextMessage)msg; + switch (counter) { + case 1: + assertEquals("First", message.getText()); + assertFalse(message.getJMSRedelivered()); + message.acknowledge(); + + break; + case 2: + assertEquals("Second", message.getText()); + assertFalse(message.getJMSRedelivered()); + session.recover(); + break; + + case 3: + assertEquals("Second", message.getText()); + assertTrue(message.getJMSRedelivered()); + message.acknowledge(); + doneCountDownLatch.countDown(); + break; + + default: + errorMessage[0] = "Got too many messages: " + counter; + doneCountDownLatch.countDown(); + } + } catch (Throwable e) { + e.printStackTrace(); + errorMessage[0] = "Got exception: " + e; + doneCountDownLatch.countDown(); + } + } + }); + connection.start(); + + if (doneCountDownLatch.await(5, TimeUnit.SECONDS)) { + if (errorMessage[0] != null) { + fail(errorMessage[0]); + } + } else { + fail("Timeout waiting for async message delivery to complete."); + } + + } + + /** + * Test to make sure that a Async recover works when using AUTO_ACKNOWLEDGE. + * + * @throws JMSException + * @throws InterruptedException + */ + public void doTestAsynchRecoverWithAutoAck() throws JMSException, InterruptedException { + + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final String errorMessage[] = new String[] {null}; + final CountDownLatch doneCountDownLatch = new CountDownLatch(1); + + MessageConsumer consumer = session.createConsumer(dest); + + MessageProducer producer = session.createProducer(dest); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage("First")); + producer.send(session.createTextMessage("Second")); + + consumer.setMessageListener(new MessageListener() { + int counter; + + public void onMessage(Message msg) { + counter++; + try { + TextMessage message = (TextMessage)msg; + switch (counter) { + case 1: + assertEquals("First", message.getText()); + assertFalse(message.getJMSRedelivered()); + break; + case 2: + // This should rollback the delivery of this message.. + // and re-deliver. + assertEquals("Second", message.getText()); + assertFalse(message.getJMSRedelivered()); + session.recover(); + break; + + case 3: + assertEquals("Second", message.getText()); + assertTrue(message.getJMSRedelivered()); + doneCountDownLatch.countDown(); + break; + + default: + errorMessage[0] = "Got too many messages: " + counter; + doneCountDownLatch.countDown(); + } + } catch (Throwable e) { + e.printStackTrace(); + errorMessage[0] = "Got exception: " + e; + doneCountDownLatch.countDown(); + } + } + }); + connection.start(); + + if (doneCountDownLatch.await(5000, TimeUnit.SECONDS)) { + if (errorMessage[0] != null) { + fail(errorMessage[0]); + } + } else { + fail("Timeout waiting for async message delivery to complete."); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTempDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTempDestinationTest.java new file mode 100644 index 0000000000..bd87b3daa8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTempDestinationTest.java @@ -0,0 +1,377 @@ +/** + * 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; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.InvalidDestinationException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.transport.vm.VMTransport; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @version + */ +public class JmsTempDestinationTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(JmsTempDestinationTest.class); + private Connection connection; + private ActiveMQConnectionFactory factory; + protected List connections = Collections.synchronizedList(new ArrayList()); + + @Override + protected void setUp() throws Exception { + factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + factory.setAlwaysSyncSend(true); + connection = factory.createConnection(); + connections.add(connection); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection conn = iter.next(); + try { + conn.close(); + } catch (Throwable e) { + } + iter.remove(); + } + } + + /** + * Make sure Temp destination can only be consumed by local connection + * + * @throws JMSException + */ + public void testTempDestOnlyConsumedByLocalConn() throws JMSException { + connection.start(); + + Session tempSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue queue = tempSession.createTemporaryQueue(); + MessageProducer producer = tempSession.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + TextMessage message = tempSession.createTextMessage("First"); + producer.send(message); + + // temp destination should not be consume when using another connection + Connection otherConnection = factory.createConnection(); + connections.add(otherConnection); + Session otherSession = otherConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue otherQueue = otherSession.createTemporaryQueue(); + MessageConsumer consumer = otherSession.createConsumer(otherQueue); + Message msg = consumer.receive(3000); + assertNull(msg); + + // should throw InvalidDestinationException when consuming a temp + // destination from another connection + try { + consumer = otherSession.createConsumer(queue); + fail("Send should fail since temp destination should be used from another connection"); + } catch (InvalidDestinationException e) { + assertTrue("failed to throw an exception", true); + } + + // should be able to consume temp destination from the same connection + consumer = tempSession.createConsumer(queue); + msg = consumer.receive(3000); + assertNotNull(msg); + + } + + /** + * Make sure that a temp queue does not drop message if there is an active + * consumers. + * + * @throws JMSException + */ + public void testTempQueueHoldsMessagesWithConsumers() throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(queue); + connection.start(); + + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + TextMessage message = session.createTextMessage("Hello"); + producer.send(message); + + Message message2 = consumer.receive(1000); + assertNotNull(message2); + assertTrue("Expected message to be a TextMessage", message2 instanceof TextMessage); + assertTrue("Expected message to be a '" + message.getText() + "'", ((TextMessage)message2).getText().equals(message.getText())); + } + + /** + * Make sure that a temp queue does not drop message if there are no active + * consumers. + * + * @throws JMSException + */ + public void testTempQueueHoldsMessagesWithoutConsumers() throws JMSException { + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createTemporaryQueue(); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + TextMessage message = session.createTextMessage("Hello"); + producer.send(message); + + connection.start(); + MessageConsumer consumer = session.createConsumer(queue); + Message message2 = consumer.receive(3000); + assertNotNull(message2); + assertTrue("Expected message to be a TextMessage", message2 instanceof TextMessage); + assertTrue("Expected message to be a '" + message.getText() + "'", ((TextMessage)message2).getText().equals(message.getText())); + + } + + /** + * Test temp queue works under load + * + * @throws JMSException + */ + public void testTmpQueueWorksUnderLoad() throws JMSException { + int count = 500; + int dataSize = 1024; + + ArrayList list = new ArrayList(count); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createTemporaryQueue(); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + byte[] data = new byte[dataSize]; + for (int i = 0; i < count; i++) { + BytesMessage message = session.createBytesMessage(); + message.writeBytes(data); + message.setIntProperty("c", i); + producer.send(message); + list.add(message); + } + + connection.start(); + MessageConsumer consumer = session.createConsumer(queue); + for (int i = 0; i < count; i++) { + Message message2 = consumer.receive(2000); + assertTrue(message2 != null); + assertEquals(i, message2.getIntProperty("c")); + assertTrue(message2.equals(list.get(i))); + } + } + + /** + * Make sure you cannot publish to a temp destination that does not exist + * anymore. + * + * @throws JMSException + * @throws InterruptedException + * @throws URISyntaxException + */ + public void testPublishFailsForClosedConnection() throws Exception { + + Connection tempConnection = factory.createConnection(); + connections.add(tempConnection); + Session tempSession = tempConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryQueue queue = tempSession.createTemporaryQueue(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.start(); + + final ActiveMQConnection activeMQConnection = (ActiveMQConnection) connection; + assertTrue("creation advisory received in time with async dispatch", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return activeMQConnection.activeTempDestinations.containsKey(queue); + } + })); + + // This message delivery should work since the temp connection is still + // open. + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + TextMessage message = session.createTextMessage("First"); + producer.send(message); + + // Closing the connection should destroy the temp queue that was + // created. + tempConnection.close(); + Thread.sleep(5000); // Wait a little bit to let the delete take effect. + + // This message delivery NOT should work since the temp connection is + // now closed. + try { + message = session.createTextMessage("Hello"); + producer.send(message); + fail("Send should fail since temp destination should not exist anymore."); + } catch (JMSException e) { + } + } + + /** + * Make sure you cannot publish to a temp destination that does not exist + * anymore. + * + * @throws JMSException + * @throws InterruptedException + */ + public void testPublishFailsForDestroyedTempDestination() throws Exception { + + Connection tempConnection = factory.createConnection(); + connections.add(tempConnection); + Session tempSession = tempConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryQueue queue = tempSession.createTemporaryQueue(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.start(); + + final ActiveMQConnection activeMQConnection = (ActiveMQConnection) connection; + assertTrue("creation advisory received in time with async dispatch", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return activeMQConnection.activeTempDestinations.containsKey(queue); + } + })); + + // This message delivery should work since the temp connection is still + // open. + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + TextMessage message = session.createTextMessage("First"); + producer.send(message); + + // deleting the Queue will cause sends to fail + queue.delete(); + Thread.sleep(5000); // Wait a little bit to let the delete take effect. + + // This message delivery NOT should work since the temp connection is + // now closed. + try { + message = session.createTextMessage("Hello"); + producer.send(message); + fail("Send should fail since temp destination should not exist anymore."); + } catch (JMSException e) { + assertTrue("failed to throw an exception", true); + } + } + + /** + * Test you can't delete a Destination with Active Subscribers + * + * @throws JMSException + */ + public void testDeleteDestinationWithSubscribersFails() throws JMSException { + Connection connection = factory.createConnection(); + connections.add(connection); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue queue = session.createTemporaryQueue(); + + connection.start(); + + session.createConsumer(queue); + + // This message delivery should NOT work since the temp connection is + // now closed. + try { + queue.delete(); + fail("Should fail as Subscribers are active"); + } catch (JMSException e) { + assertTrue("failed to throw an exception", true); + } + } + + public void testSlowConsumerDoesNotBlockFastTempUsers() throws Exception { + ActiveMQConnectionFactory advisoryConnFactory = new ActiveMQConnectionFactory("vm://localhost?asyncQueueDepth=20"); + Connection connection = advisoryConnFactory.createConnection(); + connections.add(connection); + connection.start(); + + final CountDownLatch done = new CountDownLatch(1); + final AtomicBoolean ok = new AtomicBoolean(true); + final AtomicBoolean first = new AtomicBoolean(true); + VMTransport t = ((ActiveMQConnection)connection).getTransport().narrow(VMTransport.class); + t.setTransportListener(new TransportListener() { + @Override + public void onCommand(Object command) { + // block first dispatch for a while so broker backs up, but other connection should be able to proceed + if (first.compareAndSet(true, false)) { + try { + ok.set(done.await(35, TimeUnit.SECONDS)); + LOG.info("Done waiting: " + ok.get()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onException(IOException error) { + } + + @Override + public void transportInterupted() { + } + + @Override + public void transportResumed() { + } + }); + + connection = factory.createConnection(); + connections.add(connection); + ((ActiveMQConnection)connection).setWatchTopicAdvisories(false); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + for (int i=0; i<2500; i++) { + TemporaryQueue queue = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(queue); + consumer.close(); + queue.delete(); + } + LOG.info("Done with work: " + ok.get()); + done.countDown(); + assertTrue("ok", ok.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTestSupport.java new file mode 100644 index 0000000000..5531410779 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTestSupport.java @@ -0,0 +1,186 @@ +/** + * 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; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; + +/** + * Test cases used to test the JMS message consumer. + * + * + */ +public class JmsTestSupport extends CombinationTestSupport { + + static final private AtomicLong TEST_COUNTER = new AtomicLong(); + public String userName; + public String password; + public String messageTextPrefix = ""; + + protected ConnectionFactory factory; + protected ActiveMQConnection connection; + protected BrokerService broker; + + protected List connections = Collections.synchronizedList(new ArrayList()); + + // ///////////////////////////////////////////////////////////////// + // + // Test support methods. + // + // ///////////////////////////////////////////////////////////////// + protected ActiveMQDestination createDestination(Session session, byte type) throws JMSException { + String testMethod = getName(); + if( testMethod.indexOf(" ")>0 ) { + testMethod = testMethod.substring(0, testMethod.indexOf(" ")); + } + String name = "TEST." + getClass().getName() + "." +testMethod+"."+TEST_COUNTER.getAndIncrement(); + switch (type) { + case ActiveMQDestination.QUEUE_TYPE: + return (ActiveMQDestination)session.createQueue(name); + case ActiveMQDestination.TOPIC_TYPE: + return (ActiveMQDestination)session.createTopic(name); + case ActiveMQDestination.TEMP_QUEUE_TYPE: + return (ActiveMQDestination)session.createTemporaryQueue(); + case ActiveMQDestination.TEMP_TOPIC_TYPE: + return (ActiveMQDestination)session.createTemporaryTopic(); + default: + throw new IllegalArgumentException("type: " + type); + } + } + + protected void sendMessages(Destination destination, int count) throws Exception { + ConnectionFactory factory = createConnectionFactory(); + Connection connection = factory.createConnection(); + connection.start(); + sendMessages(connection, destination, count); + connection.close(); + } + + protected void sendMessages(Connection connection, Destination destination, int count) throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + sendMessages(session, destination, count); + session.close(); + } + + protected void sendMessages(Session session, Destination destination, int count) throws JMSException { + MessageProducer producer = session.createProducer(destination); + sendMessages(session, producer, count); + producer.close(); + } + + protected void sendMessages(Session session, MessageProducer producer, int count) throws JMSException { + for (int i = 0; i < count; i++) { + producer.send(session.createTextMessage(messageTextPrefix + i)); + } + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost"); + } + + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://()/localhost?persistent=false")); + } + + protected void setUp() throws Exception { + super.setUp(); + + if (System.getProperty("basedir") == null) { + File file = new File("."); + System.setProperty("basedir", file.getAbsolutePath()); + } + + broker = createBroker(); + broker.start(); + factory = createConnectionFactory(); + connection = (ActiveMQConnection)factory.createConnection(userName, password); + connections.add(connection); + } + + protected void tearDown() throws Exception { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection conn = iter.next(); + try { + conn.close(); + } catch (Throwable e) { + } + iter.remove(); + } + broker.stop(); + super.tearDown(); + } + + protected void safeClose(Connection c) { + try { + c.close(); + } catch (Throwable e) { + } + } + + protected void safeClose(Session s) { + try { + s.close(); + } catch (Throwable e) { + } + } + + protected void safeClose(MessageConsumer c) { + try { + c.close(); + } catch (Throwable e) { + } + } + + protected void safeClose(MessageProducer p) { + try { + p.close(); + } catch (Throwable e) { + } + } + + protected void profilerPause(String prompt) throws IOException { + if (System.getProperty("profiler") != null) { + pause(prompt); + } + } + + protected void pause(String prompt) throws IOException { + System.out.println(); + System.out.println(prompt + "> Press enter to continue: "); + while (System.in.read() != '\n') { + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicCompositeSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicCompositeSendReceiveTest.java new file mode 100644 index 0000000000..a948ffa950 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicCompositeSendReceiveTest.java @@ -0,0 +1,88 @@ +/** + * 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; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Topic; + +import org.apache.activemq.test.JmsTopicSendReceiveTest; + + +/** + * + */ +public class JmsTopicCompositeSendReceiveTest extends JmsTopicSendReceiveTest { + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(JmsTopicCompositeSendReceiveTest.class); + + Destination consumerDestination2; + MessageConsumer consumer2; + + /** + * Sets a test to have a queue destination and non-persistent delivery mode. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + deliveryMode = DeliveryMode.NON_PERSISTENT; + super.setUp(); + consumerDestination2 = consumeSession.createTopic("FOO.BAR.HUMBUG2"); + LOG.info("Created consumer destination: " + consumerDestination2 + " of type: " + consumerDestination2.getClass()); + if (durable) { + LOG.info("Creating durable consumer"); + consumer2 = consumeSession.createDurableSubscriber((Topic) consumerDestination2, getName()); + } else { + consumer2 = consumeSession.createConsumer(consumerDestination2); + } + + } + + /** + * Returns the consumer subject. + * + * @return String - consumer subject + * @see org.apache.activemq.test.TestSupport#getConsumerSubject() + */ + protected String getConsumerSubject() { + return "FOO.BAR.HUMBUG"; + } + + /** + * Returns the producer subject. + * + * @return String - producer subject + * @see org.apache.activemq.test.TestSupport#getProducerSubject() + */ + protected String getProducerSubject() { + return "FOO.BAR.HUMBUG,FOO.BAR.HUMBUG2"; + } + + /** + * Test if all the messages sent are being received. + * + * @throws Exception + */ + public void testSendReceive() throws Exception { + super.testSendReceive(); + messages.clear(); + consumer2.setMessageListener(this); + assertMessagesAreReceived(); + LOG.info("" + data.length + " messages(s) received, closing down connections"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicRedeliverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicRedeliverTest.java new file mode 100644 index 0000000000..188e4cd89a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicRedeliverTest.java @@ -0,0 +1,161 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsTopicRedeliverTest extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(JmsTopicRedeliverTest.class); + + protected Connection connection; + protected Session session; + protected Session consumeSession; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected Destination consumerDestination; + protected Destination producerDestination; + protected boolean topic = true; + protected boolean durable; + protected boolean verbose; + protected long initRedeliveryDelay; + + protected void setUp() throws Exception { + super.setUp(); + + connectionFactory = createConnectionFactory(); + connection = createConnection(); + initRedeliveryDelay = ((ActiveMQConnection)connection).getRedeliveryPolicy().getInitialRedeliveryDelay(); + + if (durable) { + connection.setClientID(getClass().getName()); + } + + LOG.info("Created connection: " + connection); + + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + consumeSession = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + LOG.info("Created session: " + session); + LOG.info("Created consumeSession: " + consumeSession); + producer = session.createProducer(null); + // producer.setDeliveryMode(deliveryMode); + + LOG.info("Created producer: " + producer); + + if (topic) { + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + } else { + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + } + + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + consumerDestination.getClass()); + LOG.info("Created producer destination: " + producerDestination + " of type: " + producerDestination.getClass()); + consumer = createConsumer(); + connection.start(); + + LOG.info("Created connection: " + connection); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + /** + * Returns the consumer subject. + * + * @return String - consumer subject + * @see org.apache.activemq.test.TestSupport#getConsumerSubject() + */ + protected String getConsumerSubject() { + return "TEST"; + } + + /** + * Returns the producer subject. + * + * @return String - producer subject + * @see org.apache.activemq.test.TestSupport#getProducerSubject() + */ + protected String getProducerSubject() { + return "TEST"; + } + + /** + * Sends and consumes the messages. + * + * @throws Exception + */ + public void testRecover() throws Exception { + String text = "TEST"; + Message sendMessage = session.createTextMessage(text); + + if (verbose) { + LOG.info("About to send a message: " + sendMessage + " with text: " + text); + } + producer.send(producerDestination, sendMessage); + + // receive but don't acknowledge + Message unackMessage = consumer.receive(initRedeliveryDelay + 1000); + assertNotNull(unackMessage); + String unackId = unackMessage.getJMSMessageID(); + assertEquals(((TextMessage)unackMessage).getText(), text); + assertFalse(unackMessage.getJMSRedelivered()); + // assertEquals(unackMessage.getIntProperty("JMSXDeliveryCount"),1); + + // receive then acknowledge + consumeSession.recover(); + Message ackMessage = consumer.receive(initRedeliveryDelay + 1000); + assertNotNull(ackMessage); + ackMessage.acknowledge(); + String ackId = ackMessage.getJMSMessageID(); + assertEquals(((TextMessage)ackMessage).getText(), text); + assertTrue(ackMessage.getJMSRedelivered()); + // assertEquals(ackMessage.getIntProperty("JMSXDeliveryCount"),2); + assertEquals(unackId, ackId); + consumeSession.recover(); + assertNull(consumer.receiveNoWait()); + } + + protected MessageConsumer createConsumer() throws JMSException { + if (durable) { + LOG.info("Creating durable consumer"); + return consumeSession.createDurableSubscriber((Topic)consumerDestination, getName()); + } + return consumeSession.createConsumer(consumerDestination); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicRequestReplyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicRequestReplyTest.java new file mode 100644 index 0000000000..f5d1d2c905 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicRequestReplyTest.java @@ -0,0 +1,222 @@ +/** + * 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; + +import java.util.List; +import java.util.Vector; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.TemporaryTopic; +import javax.jms.TextMessage; + +import org.apache.activemq.test.TestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsTopicRequestReplyTest extends TestSupport implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(JmsTopicRequestReplyTest.class); + + protected boolean useAsyncConsume; + private Connection serverConnection; + private Connection clientConnection; + private MessageProducer replyProducer; + private Session serverSession; + private Destination requestDestination; + private List failures = new Vector(); + private boolean dynamicallyCreateProducer; + private String clientSideClientID; + + public void testSendAndReceive() throws Exception { + clientConnection = createConnection(); + clientConnection.setClientID("ClientConnection:" + getSubject()); + + Session session = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + clientConnection.start(); + + Destination replyDestination = createTemporaryDestination(session); + + // lets test the destination + clientSideClientID = clientConnection.getClientID(); + + // TODO + // String value = ActiveMQDestination.getClientId((ActiveMQDestination) + // replyDestination); + // assertEquals("clientID from the temporary destination must be the + // same", clientSideClientID, value); + LOG.info("Both the clientID and destination clientID match properly: " + clientSideClientID); + + /* build queues */ + MessageProducer requestProducer = session.createProducer(requestDestination); + MessageConsumer replyConsumer = session.createConsumer(replyDestination); + + /* build requestmessage */ + TextMessage requestMessage = session.createTextMessage("Olivier"); + requestMessage.setJMSReplyTo(replyDestination); + requestProducer.send(requestMessage); + + LOG.info("Sent request."); + LOG.info(requestMessage.toString()); + + Message msg = replyConsumer.receive(5000); + + if (msg instanceof TextMessage) { + TextMessage replyMessage = (TextMessage)msg; + LOG.info("Received reply."); + LOG.info(replyMessage.toString()); + assertEquals("Wrong message content", "Hello: Olivier", replyMessage.getText()); + } else { + fail("Should have received a reply by now"); + } + replyConsumer.close(); + deleteTemporaryDestination(replyDestination); + + assertEquals("Should not have had any failures: " + failures, 0, failures.size()); + } + + public void testSendAndReceiveWithDynamicallyCreatedProducer() throws Exception { + dynamicallyCreateProducer = true; + testSendAndReceive(); + } + + /** + * Use the asynchronous subscription mechanism + */ + public void onMessage(Message message) { + try { + TextMessage requestMessage = (TextMessage)message; + + LOG.info("Received request."); + LOG.info(requestMessage.toString()); + + Destination replyDestination = requestMessage.getJMSReplyTo(); + + // TODO + // String value = + // ActiveMQDestination.getClientId((ActiveMQDestination) + // replyDestination); + // assertEquals("clientID from the temporary destination must be the + // same", clientSideClientID, value); + + TextMessage replyMessage = serverSession.createTextMessage("Hello: " + requestMessage.getText()); + + replyMessage.setJMSCorrelationID(requestMessage.getJMSMessageID()); + + if (dynamicallyCreateProducer) { + replyProducer = serverSession.createProducer(replyDestination); + replyProducer.send(replyMessage); + } else { + replyProducer.send(replyDestination, replyMessage); + } + + LOG.info("Sent reply."); + LOG.info(replyMessage.toString()); + } catch (JMSException e) { + onException(e); + } + } + + /** + * Use the synchronous subscription mechanism + */ + protected void syncConsumeLoop(MessageConsumer requestConsumer) { + try { + Message message = requestConsumer.receive(5000); + if (message != null) { + onMessage(message); + } else { + LOG.error("No message received"); + } + } catch (JMSException e) { + onException(e); + } + } + + protected void setUp() throws Exception { + super.setUp(); + + serverConnection = createConnection(); + serverConnection.setClientID("serverConnection:" + getSubject()); + serverSession = serverConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + replyProducer = serverSession.createProducer(null); + + requestDestination = createDestination(serverSession); + + /* build queues */ + final MessageConsumer requestConsumer = serverSession.createConsumer(requestDestination); + if (useAsyncConsume) { + requestConsumer.setMessageListener(this); + } else { + Thread thread = new Thread(new Runnable() { + public void run() { + syncConsumeLoop(requestConsumer); + } + }); + thread.start(); + } + serverConnection.start(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + + serverConnection.close(); + clientConnection.stop(); + clientConnection.close(); + } + + protected void onException(JMSException e) { + LOG.info("Caught: " + e); + e.printStackTrace(); + failures.add(e); + } + + protected Destination createDestination(Session session) throws JMSException { + if (topic) { + return session.createTopic(getSubject()); + } + return session.createQueue(getSubject()); + } + + protected Destination createTemporaryDestination(Session session) throws JMSException { + if (topic) { + return session.createTemporaryTopic(); + } + return session.createTemporaryQueue(); + } + + protected void deleteTemporaryDestination(Destination dest) throws JMSException { + if (topic) { + ((TemporaryTopic)dest).delete(); + } else { + ((TemporaryQueue)dest).delete(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSelectorTest.java new file mode 100644 index 0000000000..e6a2503601 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSelectorTest.java @@ -0,0 +1,208 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsTopicSelectorTest extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(JmsTopicSelectorTest.class); + + protected Connection connection; + protected Session session; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected Destination consumerDestination; + protected Destination producerDestination; + protected boolean topic = true; + protected boolean durable; + protected int deliveryMode = DeliveryMode.PERSISTENT; + + public void setUp() throws Exception { + super.setUp(); + + connectionFactory = createConnectionFactory(); + connection = createConnection(); + if (durable) { + connection.setClientID(getClass().getName()); + } + + LOG.info("Created connection: " + connection); + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + LOG.info("Created session: " + session); + + if (topic) { + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + } else { + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + } + + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + consumerDestination.getClass()); + LOG.info("Created producer destination: " + producerDestination + " of type: " + producerDestination.getClass()); + producer = session.createProducer(producerDestination); + producer.setDeliveryMode(deliveryMode); + + LOG.info("Created producer: " + producer + " delivery mode = " + (deliveryMode == DeliveryMode.PERSISTENT ? "PERSISTENT" : "NON_PERSISTENT")); + connection.start(); + } + + public void tearDown() throws Exception { + session.close(); + connection.close(); + } + + protected MessageConsumer createConsumer(String selector) throws JMSException { + if (durable) { + LOG.info("Creating durable consumer"); + return session.createDurableSubscriber((Topic)consumerDestination, getName(), selector, false); + } + return session.createConsumer(consumerDestination, selector); + } + + public void sendMessages() throws Exception { + TextMessage message = session.createTextMessage("1"); + message.setIntProperty("id", 1); + message.setJMSType("a"); + message.setStringProperty("stringProperty", "a"); + message.setLongProperty("longProperty", 1); + message.setBooleanProperty("booleanProperty", true); + producer.send(message); + + message = session.createTextMessage("2"); + message.setIntProperty("id", 2); + message.setJMSType("a"); + message.setStringProperty("stringProperty", "a"); + message.setLongProperty("longProperty", 1); + message.setBooleanProperty("booleanProperty", false); + producer.send(message); + + message = session.createTextMessage("3"); + message.setIntProperty("id", 3); + message.setJMSType("a"); + message.setStringProperty("stringProperty", "a"); + message.setLongProperty("longProperty", 1); + message.setBooleanProperty("booleanProperty", true); + producer.send(message); + + message = session.createTextMessage("4"); + message.setIntProperty("id", 4); + message.setJMSType("b"); + message.setStringProperty("stringProperty", "b"); + message.setLongProperty("longProperty", 2); + message.setBooleanProperty("booleanProperty", false); + producer.send(message); + + message = session.createTextMessage("5"); + message.setIntProperty("id", 5); + message.setJMSType("c"); + message.setStringProperty("stringProperty", "c"); + message.setLongProperty("longProperty", 3); + message.setBooleanProperty("booleanProperty", true); + producer.send(message); + } + + public void consumeMessages(int remaining) throws Exception { + consumer = createConsumer(null); + for (int i = 0; i < remaining; i++) { + consumer.receive(1000); + } + consumer.close(); + + } + + public void testEmptyPropertySelector() throws Exception { + int remaining = 5; + Message message = null; + consumer = createConsumer(""); + sendMessages(); + while (true) { + message = consumer.receive(1000); + if (message == null) { + break; + } + + remaining--; + } + assertEquals(remaining, 0); + consumer.close(); + consumeMessages(remaining); + } + + public void testPropertySelector() throws Exception { + int remaining = 5; + Message message = null; + consumer = createConsumer("stringProperty = 'a' and longProperty = 1 and booleanProperty = true"); + sendMessages(); + while (true) { + message = consumer.receive(1000); + if (message == null) { + break; + } + String text = ((TextMessage)message).getText(); + if (!text.equals("1") && !text.equals("3")) { + fail("unexpected message: " + text); + } + remaining--; + } + assertEquals(remaining, 3); + consumer.close(); + consumeMessages(remaining); + + } + + public void testJMSPropertySelector() throws Exception { + int remaining = 5; + Message message = null; + consumer = createConsumer("JMSType = 'a' and stringProperty = 'a'"); + sendMessages(); + while (true) { + message = consumer.receive(1000); + if (message == null) { + break; + } + String text = ((TextMessage)message).getText(); + if (!text.equals("1") && !text.equals("2") && !text.equals("3")) { + fail("unexpected message: " + text); + } + remaining--; + } + assertEquals(remaining, 2); + consumer.close(); + consumeMessages(remaining); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveSubscriberTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveSubscriberTest.java new file mode 100644 index 0000000000..7cb09ea505 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveSubscriberTest.java @@ -0,0 +1,36 @@ +/** + * 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; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Topic; +import javax.jms.TopicSession; + +/** + * + */ +public class JmsTopicSendReceiveSubscriberTest extends JmsTopicSendReceiveTest { + protected MessageConsumer createConsumer() throws JMSException { + if (durable) { + return super.createConsumer(); + } else { + TopicSession topicSession = (TopicSession)session; + return topicSession.createSubscriber((Topic)consumerDestination, null, false); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveTest.java new file mode 100644 index 0000000000..fd91ec4fa2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveTest.java @@ -0,0 +1,92 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsTopicSendReceiveTest extends JmsSendReceiveTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(JmsTopicSendReceiveTest.class); + + protected Connection connection; + + protected void setUp() throws Exception { + super.setUp(); + + connectionFactory = createConnectionFactory(); + connection = createConnection(); + if (durable) { + connection.setClientID(getClass().getName()); + } + + LOG.info("Created connection: " + connection); + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + LOG.info("Created session: " + session); + producer = session.createProducer(null); + producer.setDeliveryMode(deliveryMode); + + LOG.info("Created producer: " + producer + " delivery mode = " + (deliveryMode == DeliveryMode.PERSISTENT ? "PERSISTENT" : "NON_PERSISTENT")); + + if (topic) { + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + } else { + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + } + + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + consumerDestination.getClass()); + LOG.info("Created producer destination: " + producerDestination + " of type: " + producerDestination.getClass()); + consumer = createConsumer(); + consumer.setMessageListener(this); + connection.start(); + + // log.info("Created connection: " + connection); + } + + protected MessageConsumer createConsumer() throws JMSException { + if (durable) { + LOG.info("Creating durable consumer"); + return session.createDurableSubscriber((Topic)consumerDestination, getName()); + } + return session.createConsumer(consumerDestination); + } + + protected void tearDown() throws Exception { + LOG.info("Dumping stats..."); + // connectionFactory.getStats().reset(); + + LOG.info("Closing down connection"); + + /** TODO we should be able to shut down properly */ + session.close(); + connection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveWithTwoConnectionsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveWithTwoConnectionsTest.java new file mode 100644 index 0000000000..b56c15de35 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveWithTwoConnectionsTest.java @@ -0,0 +1,113 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +/** + * @version + */ +public class JmsTopicSendReceiveWithTwoConnectionsTest extends JmsSendReceiveTestSupport { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(JmsTopicSendReceiveWithTwoConnectionsTest.class); + + protected Connection sendConnection; + protected Connection receiveConnection; + protected Session receiveSession; + + protected void setUp() throws Exception { + super.setUp(); + + connectionFactory = createConnectionFactory(); + + sendConnection = createSendConnection(); + sendConnection.start(); + + receiveConnection = createReceiveConnection(); + receiveConnection.start(); + + LOG.info("Created sendConnection: " + sendConnection); + LOG.info("Created receiveConnection: " + receiveConnection); + + session = createSendSession(sendConnection); + receiveSession = createReceiveSession(receiveConnection); + + LOG.info("Created sendSession: " + session); + LOG.info("Created receiveSession: " + receiveSession); + + producer = session.createProducer(null); + producer.setDeliveryMode(deliveryMode); + + LOG.info("Created producer: " + producer + " delivery mode = " + + (deliveryMode == DeliveryMode.PERSISTENT ? "PERSISTENT" : "NON_PERSISTENT")); + + if (topic) { + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + } else { + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + } + + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + + consumerDestination.getClass()); + LOG.info("Created producer destination: " + producerDestination + " of type: " + + producerDestination.getClass()); + + consumer = createConsumer(receiveSession, consumerDestination); + consumer.setMessageListener(this); + + LOG.info("Started connections"); + } + + protected Session createReceiveSession(Connection receiveConnection) throws Exception { + return receiveConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + protected Session createSendSession(Connection sendConnection) throws Exception { + return sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + protected Connection createReceiveConnection() throws Exception { + return createConnection(); + } + + protected Connection createSendConnection() throws Exception { + return createConnection(); + } + + protected MessageConsumer createConsumer(Session session, Destination dest) throws JMSException { + return session.createConsumer(dest); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + } + + protected void tearDown() throws Exception { + session.close(); + receiveSession.close(); + sendConnection.close(); + receiveConnection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveWithTwoConnectionsWithJMXTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveWithTwoConnectionsWithJMXTest.java new file mode 100644 index 0000000000..da2c80cdcd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendReceiveWithTwoConnectionsWithJMXTest.java @@ -0,0 +1,29 @@ +/** + * 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; + +/** + * + * + */ +public class JmsTopicSendReceiveWithTwoConnectionsWithJMXTest extends + JmsTopicSendReceiveWithTwoConnectionsTest { + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false&broker.useJmx=true"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendSameMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendSameMessageTest.java new file mode 100644 index 0000000000..9a92e4994c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicSendSameMessageTest.java @@ -0,0 +1,48 @@ +/** + * 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; + +import javax.jms.TextMessage; + +/** + * + */ +public class JmsTopicSendSameMessageTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(JmsTopicSendSameMessageTest.class); + + public void testSendReceive() throws Exception { + messages.clear(); + + TextMessage message = session.createTextMessage(); + + for (int i = 0; i < data.length; i++) { + message.setText(data[i]); + message.setStringProperty("stringProperty", data[i]); + message.setIntProperty("intProperty", i); + + if (verbose) { + LOG.info("About to send a message: " + message + " with text: " + data[i]); + } + + producer.send(producerDestination, message); + } + + assertMessagesAreReceived(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicTransactionTest.java new file mode 100644 index 0000000000..cf5cdc0c03 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicTransactionTest.java @@ -0,0 +1,38 @@ +/** + * 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; + +import org.apache.activemq.test.JmsResourceProvider; + + +/** + * + */ +public class JmsTopicTransactionTest extends JmsTransactionTestSupport { + + /** + * @see org.apache.activemq.JmsTransactionTestSupport#getJmsResourceProvider() + */ + protected JmsResourceProvider getJmsResourceProvider() { + JmsResourceProvider p = new JmsResourceProvider(); + p.setTopic(true); + p.setDurableName("testsub"); + p.setClientID("testclient"); + return p; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicWildcardSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicWildcardSendReceiveTest.java new file mode 100644 index 0000000000..eeb599988a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/JmsTopicWildcardSendReceiveTest.java @@ -0,0 +1,209 @@ +/** + * 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; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.test.JmsTopicSendReceiveTest; + +/** + * + */ +public class JmsTopicWildcardSendReceiveTest extends JmsTopicSendReceiveTest { + + private String destination1String = "TEST.ONE.ONE"; + private String destination2String = "TEST.ONE.ONE.ONE"; + private String destination3String = "TEST.ONE.TWO"; + private String destination4String = "TEST.TWO.ONE"; + + protected void setUp() throws Exception { + topic = true; + durable = false; + deliveryMode = DeliveryMode.NON_PERSISTENT; + super.setUp(); + } + + protected String getConsumerSubject() { + return "FOO.>"; + } + + protected String getProducerSubject() { + return "FOO.BAR.HUMBUG"; + } + + public void testReceiveWildcardTopicEndAsterisk() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createTopic(destination1String); + ActiveMQDestination destination3 = (ActiveMQDestination)session.createTopic(destination3String); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + ActiveMQDestination destination6 = (ActiveMQDestination)session.createTopic("TEST.ONE.*"); + consumer = session.createConsumer(destination6); + sendMessage(session, destination1, destination1String); + sendMessage(session, destination3, destination3String); + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + assertNull(consumer.receiveNoWait()); + } + + public void testReceiveWildcardTopicEndGreaterThan() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createTopic(destination1String); + ActiveMQDestination destination2 = (ActiveMQDestination)session.createTopic(destination2String); + ActiveMQDestination destination3 = (ActiveMQDestination)session.createTopic(destination3String); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + ActiveMQDestination destination7 = (ActiveMQDestination)session.createTopic("TEST.ONE.>"); + consumer = session.createConsumer(destination7); + sendMessage(session, destination1, destination1String); + sendMessage(session, destination2, destination2String); + sendMessage(session, destination3, destination3String); + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination2String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + if (!(text.equals(destination1String) || text.equals(destination2String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + if (!(text.equals(destination1String) || text.equals(destination2String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + assertNull(consumer.receiveNoWait()); + } + + public void testReceiveWildcardTopicMidAsterisk() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createTopic(destination1String); + ActiveMQDestination destination4 = (ActiveMQDestination)session.createTopic(destination4String); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + ActiveMQDestination destination8 = (ActiveMQDestination)session.createTopic("TEST.*.ONE"); + consumer = session.createConsumer(destination8); + sendMessage(session, destination1, destination1String); + sendMessage(session, destination4, destination4String); + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination4String))) { + fail("unexpected message:" + text); + } + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination4String))) { + fail("unexpected message:" + text); + } + assertNull(consumer.receiveNoWait()); + + } + + public void testReceiveWildcardTopicMatchDoubleWildcard() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createTopic("a.*.>.>"); + ActiveMQDestination destination2 = (ActiveMQDestination)session.createTopic("a.b"); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + + consumer = session.createConsumer(destination1); + sendMessage(session, destination2, destination3String); + + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + + assertNull(consumer.receiveNoWait()); + } + + public void testReceiveWildcardTopicMatchSinglePastTheEndWildcard() throws Exception { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQDestination destination1 = (ActiveMQDestination)session.createTopic("a.>"); + ActiveMQDestination destination2 = (ActiveMQDestination)session.createTopic("a"); + + Message m = null; + MessageConsumer consumer = null; + String text = null; + + + consumer = session.createConsumer(destination1); + sendMessage(session, destination2, destination3String); + + m = consumer.receive(1000); + assertNotNull(m); + text = ((TextMessage)m).getText(); + if (!(text.equals(destination1String) || text.equals(destination3String))) { + fail("unexpected message:" + text); + } + + assertNull(consumer.receiveNoWait()); + } + + + + private void sendMessage(Session session, Destination destination, String text) throws JMSException { + MessageProducer producer = session.createProducer(destination); + producer.send(session.createTextMessage(text)); + producer.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LargeMessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LargeMessageTestSupport.java new file mode 100644 index 0000000000..fc772185cf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LargeMessageTestSupport.java @@ -0,0 +1,197 @@ +/** + * 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; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.IdGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class LargeMessageTestSupport extends ClientTestSupport implements MessageListener { + + protected static final int LARGE_MESSAGE_SIZE = 128 * 1024; + protected static final int MESSAGE_COUNT = 100; + + private static final Logger LOG = LoggerFactory.getLogger(LargeMessageTestSupport.class); + + protected Connection producerConnection; + protected Connection consumerConnection; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected Session producerSession; + protected Session consumerSession; + protected byte[] largeMessageData; + protected Destination destination; + protected boolean isTopic = true; + protected boolean isDurable = true; + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected IdGenerator idGen = new IdGenerator(); + protected boolean validMessageConsumption = true; + protected AtomicInteger messageCount = new AtomicInteger(0); + + protected int prefetchValue = 10000000; + + protected Destination createDestination() { + String subject = getClass().getName(); + if (isTopic) { + return new ActiveMQTopic(subject); + } else { + return new ActiveMQQueue(subject); + } + } + + protected MessageConsumer createConsumer() throws JMSException { + if (isTopic && isDurable) { + return consumerSession.createDurableSubscriber((Topic)destination, idGen.generateId()); + } else { + return consumerSession.createConsumer(destination); + } + } + + public void setUp() throws Exception { + super.setUp(); + ClientTestSupport.removeMessageStore(); + LOG.info("Setting up . . . . . "); + messageCount.set(0); + + destination = createDestination(); + largeMessageData = new byte[LARGE_MESSAGE_SIZE]; + for (int i = 0; i < LARGE_MESSAGE_SIZE; i++) { + if (i % 2 == 0) { + largeMessageData[i] = 'a'; + } else { + largeMessageData[i] = 'z'; + } + } + + try { + // allow the broker to start + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new JMSException(e.getMessage()); + } + + ActiveMQConnectionFactory fac = getConnectionFactory(); + producerConnection = fac.createConnection(); + setPrefetchPolicy((ActiveMQConnection)producerConnection); + producerConnection.start(); + + consumerConnection = fac.createConnection(); + setPrefetchPolicy((ActiveMQConnection)consumerConnection); + consumerConnection.setClientID(idGen.generateId()); + consumerConnection.start(); + producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = producerSession.createProducer(createDestination()); + producer.setDeliveryMode(deliveryMode); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = createConsumer(); + consumer.setMessageListener(this); + LOG.info("Setup complete"); + } + + protected void setPrefetchPolicy(ActiveMQConnection activeMQConnection) { + activeMQConnection.getPrefetchPolicy().setTopicPrefetch(prefetchValue); + activeMQConnection.getPrefetchPolicy().setQueuePrefetch(prefetchValue); + activeMQConnection.getPrefetchPolicy().setDurableTopicPrefetch(prefetchValue); + activeMQConnection.getPrefetchPolicy().setQueueBrowserPrefetch(prefetchValue); + activeMQConnection.getPrefetchPolicy().setOptimizeDurableTopicPrefetch(prefetchValue); + } + + public void tearDown() throws Exception { + Thread.sleep(1000); + producerConnection.close(); + consumerConnection.close(); + + super.tearDown(); + + largeMessageData = null; + } + + protected boolean isSame(BytesMessage msg1) throws Exception { + boolean result = false; + ((ActiveMQMessage)msg1).setReadOnlyBody(true); + + for (int i = 0; i < LARGE_MESSAGE_SIZE; i++) { + result = msg1.readByte() == largeMessageData[i]; + if (!result) { + break; + } + } + + return result; + } + + public void onMessage(Message msg) { + try { + BytesMessage ba = (BytesMessage)msg; + validMessageConsumption &= isSame(ba); + assertTrue(ba.getBodyLength() == LARGE_MESSAGE_SIZE); + if (messageCount.incrementAndGet() >= MESSAGE_COUNT) { + synchronized (messageCount) { + messageCount.notify(); + } + } + LOG.info("got message = " + messageCount); + if (messageCount.get() % 50 == 0) { + LOG.info("count = " + messageCount); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void testLargeMessages() throws Exception { + for (int i = 0; i < MESSAGE_COUNT; i++) { + LOG.info("Sending message: " + i); + BytesMessage msg = producerSession.createBytesMessage(); + msg.writeBytes(largeMessageData); + producer.send(msg); + } + long now = System.currentTimeMillis(); + while (now + 60000 > System.currentTimeMillis() && messageCount.get() < MESSAGE_COUNT) { + LOG.info("message count = " + messageCount); + synchronized (messageCount) { + messageCount.wait(1000); + } + } + LOG.info("Finished count = " + messageCount); + assertTrue("Not enough messages - expected " + MESSAGE_COUNT + " but got " + messageCount, messageCount.get() == MESSAGE_COUNT); + assertTrue("received messages are not valid", validMessageConsumption); + Thread.sleep(1000); + LOG.info("FINAL count = " + messageCount); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LargeStreamletTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LargeStreamletTest.java new file mode 100644 index 0000000000..d624d368c5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LargeStreamletTest.java @@ -0,0 +1,162 @@ +/** + * 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; + +/** + * 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. + */ + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Destination; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author rnewson + */ +public final class LargeStreamletTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(LargeStreamletTest.class); + private static final String BROKER_URL = "vm://localhost?broker.persistent=false"; + private static final int BUFFER_SIZE = 1 * 1024; + private static final int MESSAGE_COUNT = 10 * 1024; + + protected Exception writerException; + protected Exception readerException; + + private final AtomicInteger totalRead = new AtomicInteger(); + private final AtomicInteger totalWritten = new AtomicInteger(); + private final AtomicBoolean stopThreads = new AtomicBoolean(false); + + public void testStreamlets() throws Exception { + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL); + + final ActiveMQConnection connection = (ActiveMQConnection)factory.createConnection(); + connection.start(); + try { + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + try { + final Destination destination = session.createQueue("wibble"); + final Thread readerThread = new Thread(new Runnable() { + + @Override + public void run() { + totalRead.set(0); + try { + final InputStream inputStream = connection.createInputStream(destination); + try { + int read; + final byte[] buf = new byte[BUFFER_SIZE]; + while (!stopThreads.get() && (read = inputStream.read(buf)) != -1) { + totalRead.addAndGet(read); + } + } finally { + inputStream.close(); + } + } catch (Exception e) { + readerException = e; + e.printStackTrace(); + } finally { + LOG.info(totalRead + " total bytes read."); + } + } + }); + + final Thread writerThread = new Thread(new Runnable() { + private final Random random = new Random(); + + @Override + public void run() { + totalWritten.set(0); + int count = MESSAGE_COUNT; + try { + final OutputStream outputStream = connection.createOutputStream(destination); + try { + final byte[] buf = new byte[BUFFER_SIZE]; + random.nextBytes(buf); + while (count > 0 && !stopThreads.get()) { + outputStream.write(buf); + totalWritten.addAndGet(buf.length); + count--; + } + } finally { + outputStream.close(); + } + } catch (Exception e) { + writerException = e; + e.printStackTrace(); + } finally { + LOG.info(totalWritten + " total bytes written."); + } + } + }); + + readerThread.start(); + writerThread.start(); + + // Wait till reader is has finished receiving all the messages + // or he has stopped + // receiving messages. + Thread.sleep(1000); + int lastRead = totalRead.get(); + while (readerThread.isAlive()) { + readerThread.join(1000); + // No progress?? then stop waiting.. + if (lastRead == totalRead.get()) { + break; + } + lastRead = totalRead.get(); + } + + stopThreads.set(true); + + assertTrue("Should not have received a reader exception", readerException == null); + assertTrue("Should not have received a writer exception", writerException == null); + + assertEquals("Not all messages accounted for", totalWritten.get(), totalRead.get()); + + } finally { + session.close(); + } + } finally { + connection.close(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LoadTestBurnIn.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LoadTestBurnIn.java new file mode 100644 index 0000000000..4462844bd6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/LoadTestBurnIn.java @@ -0,0 +1,171 @@ +/** + * 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; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; + +import junit.framework.Test; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQDestination; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Small burn test moves sends a moderate amount of messages through the broker, + * to checking to make sure that the broker does not lock up after a while of + * sustained messaging. + * + * + */ +public class LoadTestBurnIn extends JmsTestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(LoadTestBurnIn.class); + + public ActiveMQDestination destination; + public int deliveryMode; + public byte destinationType; + public boolean durableConsumer; + public int messageCount = 50000; + public int messageSize = 1024; + + public static Test suite() { + return suite(LoadTestBurnIn.class); + } + + protected void setUp() throws Exception { + LOG.info("Start: " + getName()); + super.setUp(); + } + + protected void tearDown() throws Exception { + try { + super.tearDown(); + } catch (Throwable e) { + e.printStackTrace(System.out); + } finally { + LOG.info("End: " + getName()); + } + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://(tcp://localhost:0)?useJmx=true")); + // return BrokerFactory.createBroker(new + // URI("xbean:org/apache/activemq/broker/store/loadtester.xml")); + } + + protected ConnectionFactory createConnectionFactory() throws URISyntaxException, IOException { + return new ActiveMQConnectionFactory(((TransportConnector)broker.getTransportConnectors().get(0)) + .getServer().getConnectURI()); + } + + public void initCombosForTestSendReceive() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + addCombinationValues("durableConsumer", new Object[] {Boolean.TRUE}); + addCombinationValues("messageSize", new Object[] {Integer.valueOf(101), Integer.valueOf(102), + Integer.valueOf(103), Integer.valueOf(104), + Integer.valueOf(105), Integer.valueOf(106), + Integer.valueOf(107), Integer.valueOf(108)}); + } + + public void testSendReceive() throws Exception { + + // Durable consumer combination is only valid with topics + if (durableConsumer && destinationType != ActiveMQDestination.TOPIC_TYPE) { + return; + } + + connection.setClientID(getName()); + connection.getPrefetchPolicy().setAll(1000); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(session, destinationType); + MessageConsumer consumer; + if (durableConsumer) { + consumer = session.createDurableSubscriber((Topic)destination, "sub1:" + + System.currentTimeMillis()); + } else { + consumer = session.createConsumer(destination); + } + profilerPause("Ready: "); + + final CountDownLatch producerDoneLatch = new CountDownLatch(1); + + // Send the messages, async + new Thread() { + public void run() { + Connection connection2 = null; + try { + connection2 = factory.createConnection(); + Session session = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + for (int i = 0; i < messageCount; i++) { + BytesMessage m = session.createBytesMessage(); + m.writeBytes(new byte[messageSize]); + producer.send(m); + } + producer.close(); + } catch (JMSException e) { + e.printStackTrace(); + } finally { + safeClose(connection2); + producerDoneLatch.countDown(); + } + + } + }.start(); + + // Make sure all the messages were delivered. + Message message = null; + for (int i = 0; i < messageCount; i++) { + message = consumer.receive(5000); + assertNotNull("Did not get message: " + i, message); + } + + profilerPause("Done: "); + + assertNull(consumer.receiveNoWait()); + message.acknowledge(); + + // Make sure the producer thread finishes. + assertTrue(producerDoneLatch.await(5, TimeUnit.SECONDS)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/MessageEvictionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/MessageEvictionTest.java new file mode 100644 index 0000000000..b079070296 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/MessageEvictionTest.java @@ -0,0 +1,288 @@ +/** + * 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; + +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 java.util.ArrayList; +import java.util.List; +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 javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.ConstantPendingMessageLimitStrategy; +import org.apache.activemq.broker.region.policy.FilePendingSubscriberMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.OldestMessageEvictionStrategy; +import org.apache.activemq.broker.region.policy.PendingSubscriberMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingSubscriberMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageEvictionTest { + static final Logger LOG = LoggerFactory.getLogger(MessageEvictionTest.class); + private BrokerService broker; + private ConnectionFactory connectionFactory; + Connection connection; + private Session session; + private Topic destination; + private final String destinationName = "verifyEvection"; + protected int numMessages = 2000; + protected String payload = new String(new byte[1024*2]); + + public void setUp(PendingSubscriberMessageStoragePolicy pendingSubscriberPolicy) throws Exception { + broker = createBroker(pendingSubscriberPolicy); + broker.start(); + connectionFactory = createConnectionFactory(); + connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = session.createTopic(destinationName); + } + + @After + public void tearDown() throws Exception { + connection.stop(); + broker.stop(); + } + + @Test + public void testMessageEvictionMemoryUsageFileCursor() throws Exception { + setUp(new FilePendingSubscriberMessageStoragePolicy()); + doTestMessageEvictionMemoryUsage(); + } + + @Test + public void testMessageEvictionMemoryUsageVmCursor() throws Exception { + setUp(new VMPendingSubscriberMessageStoragePolicy()); + doTestMessageEvictionMemoryUsage(); + } + + @Test + public void testMessageEvictionDiscardedAdvisory() throws Exception { + setUp(new VMPendingSubscriberMessageStoragePolicy()); + + ExecutorService executor = Executors.newSingleThreadExecutor(); + final CountDownLatch consumerRegistered = new CountDownLatch(1); + final CountDownLatch gotAdvisory = new CountDownLatch(1); + final CountDownLatch advisoryIsGood = new CountDownLatch(1); + + executor.execute(new Runnable() { + @Override + public void run() { + try { + ActiveMQTopic discardedAdvisoryDestination = + AdvisorySupport.getMessageDiscardedAdvisoryTopic(destination); + // use separate session rather than asyncDispatch on consumer session + // as we want consumer session to block + Session advisorySession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = advisorySession.createConsumer(discardedAdvisoryDestination); + consumer.setMessageListener(new MessageListener() { + int advisoriesReceived = 0; + @Override + public void onMessage(Message message) { + try { + LOG.info("advisory:" + message); + ActiveMQMessage activeMQMessage = (ActiveMQMessage) message; + assertNotNull(activeMQMessage.getStringProperty(AdvisorySupport.MSG_PROPERTY_CONSUMER_ID)); + assertEquals(++advisoriesReceived, activeMQMessage.getIntProperty(AdvisorySupport.MSG_PROPERTY_DISCARDED_COUNT)); + message.acknowledge(); + advisoryIsGood.countDown(); + } catch (JMSException e) { + e.printStackTrace(); + fail(e.toString()); + } finally { + gotAdvisory.countDown(); + } + } + }); + consumerRegistered.countDown(); + gotAdvisory.await(120, TimeUnit.SECONDS); + consumer.close(); + advisorySession.close(); + } catch (Exception e) { + e.printStackTrace(); + fail(e.toString()); + } + } + }); + assertTrue("we have an advisory consumer", consumerRegistered.await(60, TimeUnit.SECONDS)); + doTestMessageEvictionMemoryUsage(); + assertTrue("got an advisory for discarded", gotAdvisory.await(0, TimeUnit.SECONDS)); + assertTrue("advisory is good",advisoryIsGood.await(0, TimeUnit.SECONDS)); + } + + public void doTestMessageEvictionMemoryUsage() throws Exception { + + ExecutorService executor = Executors.newCachedThreadPool(); + final CountDownLatch doAck = new CountDownLatch(1); + final CountDownLatch ackDone = new CountDownLatch(1); + final CountDownLatch consumerRegistered = new CountDownLatch(1); + executor.execute(new Runnable() { + @Override + public void run() { + try { + final MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + // very slow, only ack once + doAck.await(60, TimeUnit.SECONDS); + LOG.info("acking: " + message.getJMSMessageID()); + message.acknowledge(); + ackDone.countDown(); + } catch (Exception e) { + e.printStackTrace(); + fail(e.toString()); + } finally { + consumerRegistered.countDown(); + ackDone.countDown(); + } + } + }); + consumerRegistered.countDown(); + ackDone.await(60, TimeUnit.SECONDS); + consumer.close(); + } catch (Exception e) { + e.printStackTrace(); + fail(e.toString()); + } + } + }); + + assertTrue("we have a consumer", consumerRegistered.await(10, TimeUnit.SECONDS)); + + final AtomicInteger sent = new AtomicInteger(0); + final CountDownLatch sendDone = new CountDownLatch(1); + executor.execute(new Runnable() { + @Override + public void run() { + MessageProducer producer; + try { + producer = session.createProducer(destination); + for (int i=0; i< numMessages; i++) { + producer.send(session.createTextMessage(payload)); + sent.incrementAndGet(); + TimeUnit.MILLISECONDS.sleep(10); + } + producer.close(); + sendDone.countDown(); + } catch (Exception e) { + sendDone.countDown(); + e.printStackTrace(); + fail(e.toString()); + } + } + }); + + assertTrue("messages sending done", sendDone.await(180, TimeUnit.SECONDS)); + assertEquals("all message were sent", numMessages, sent.get()); + + doAck.countDown(); + executor.shutdown(); + executor.awaitTermination(30, TimeUnit.SECONDS); + + assertTrue("usage goes to 0 once consumer goes away", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == TestSupport.getDestination(broker, + ActiveMQDestination.transform(destination)).getMemoryUsage().getPercentUsage(); + } + })); + } + + BrokerService createBroker(PendingSubscriberMessageStoragePolicy pendingSubscriberPolicy) throws Exception { + BrokerService brokerService = new BrokerService(); + brokerService.addConnector("tcp://localhost:0"); + brokerService.setUseJmx(false); + brokerService.setDeleteAllMessagesOnStartup(true); + + // spooling to disk early so topic memory limit is not reached + brokerService.getSystemUsage().getMemoryUsage().setLimit(500*1024); + + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setTopic(">"); + + entry.setAdvisoryForDiscardingMessages(true); + + // so consumer does not get over run while blocked limit the prefetch + entry.setTopicPrefetch(50); + + + entry.setPendingSubscriberPolicy(pendingSubscriberPolicy); + + // limit the number of outstanding messages, large enough to use the file store + // or small enough not to blow memory limit + int pendingMessageLimit = 50; + if (pendingSubscriberPolicy instanceof FilePendingSubscriberMessageStoragePolicy) { + pendingMessageLimit = 500; + } + ConstantPendingMessageLimitStrategy pendingMessageLimitStrategy = new ConstantPendingMessageLimitStrategy(); + pendingMessageLimitStrategy.setLimit(pendingMessageLimit); + entry.setPendingMessageLimitStrategy(pendingMessageLimitStrategy); + + // to keep the limit in check and up to date rather than just the first few, evict some + OldestMessageEvictionStrategy messageEvictionStrategy = new OldestMessageEvictionStrategy(); + // whether to check expiry before eviction, default limit 1000 is fine as no ttl set in this test + //messageEvictionStrategy.setEvictExpiredMessagesHighWatermark(1000); + entry.setMessageEvictionStrategy(messageEvictionStrategy); + + // let evicted messaged disappear + entry.setDeadLetterStrategy(null); + policyEntries.add(entry); + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + brokerService.setDestinationPolicy(policyMap); + + return brokerService; + } + + ConnectionFactory createConnectionFactory() throws Exception { + String url = broker.getTransportConnectors().get(0).getServer().getConnectURI().toString(); + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url); + factory.setWatchTopicAdvisories(false); + return factory; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/MessageListenerRedeliveryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/MessageListenerRedeliveryTest.java new file mode 100644 index 0000000000..0fb9728aa5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/MessageListenerRedeliveryTest.java @@ -0,0 +1,357 @@ +/** + * 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; + +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageListenerRedeliveryTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(MessageListenerRedeliveryTest.class); + + private Connection connection; + + @Override + protected void setUp() throws Exception { + connection = createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + } + + protected RedeliveryPolicy getRedeliveryPolicy() { + RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); + redeliveryPolicy.setInitialRedeliveryDelay(0); + redeliveryPolicy.setRedeliveryDelay(1000); + redeliveryPolicy.setMaximumRedeliveries(3); + redeliveryPolicy.setBackOffMultiplier((short)2); + redeliveryPolicy.setUseExponentialBackOff(true); + return redeliveryPolicy; + } + + protected Connection createConnection() throws Exception { + 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; + private final Session session; + + public TestMessageListener(Session session) { + this.session = session; + } + + @Override + public void onMessage(Message message) { + try { + LOG.info("Message Received: " + message); + counter++; + if (counter <= 4) { + LOG.info("Message Rollback."); + session.rollback(); + } else { + LOG.info("Message Commit."); + message.acknowledge(); + session.commit(); + } + } catch (JMSException e) { + LOG.error("Error when rolling back transaction"); + } + } + } + + public void testQueueRollbackConsumerListener() throws JMSException { + connection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + MessageProducer producer = createProducer(session, queue); + Message message = createTextMessage(session); + producer.send(message); + session.commit(); + + MessageConsumer consumer = session.createConsumer(queue); + + ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer)consumer; + mc.setRedeliveryPolicy(getRedeliveryPolicy()); + + 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); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + // 2nd redeliver (redelivery after 1 sec) + assertEquals(3, listener.counter); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + } + // 3rd redeliver (redelivery after 2 seconds) - it should give up after + // that + assertEquals(4, listener.counter); + + // 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); + + try { + Thread.sleep(1500); + } catch (InterruptedException e) { + } + // no redelivery, counter should still be 4 + assertEquals(5, listener.counter); + + session.close(); + } + + public void testQueueRollbackSessionListener() throws JMSException { + connection.start(); + + Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + MessageProducer producer = createProducer(session, queue); + Message message = createTextMessage(session); + producer.send(message); + session.commit(); + + MessageConsumer consumer = session.createConsumer(queue); + + ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer)consumer; + mc.setRedeliveryPolicy(getRedeliveryPolicy()); + + 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) { + + } + // second try (redelivery after 1 sec) + assertEquals(3, listener.counter); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + + } + // third try (redelivery after 2 seconds) - it should give up after that + assertEquals(4, listener.counter); + + // 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); + + try { + Thread.sleep(1500); + } catch (InterruptedException e) { + // ignore + } + // no redelivery, counter should still be 4 + assertEquals(5, listener.counter); + + session.close(); + } + + public void testQueueSessionListenerExceptionRetry() throws Exception { + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("queue-" + getName()); + 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 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(getName() + " force a redelivery"); + } + // new blood + count.set(0); + gotMessage.countDown(); + } + }); + + assertTrue("got message before retry expiry", gotMessage.await(20, TimeUnit.SECONDS)); + + for (int i=0; i 0); + assertEquals("received what was committed", sent.get(), received); + } + + protected void waitForBlocked(final AtomicBoolean done) + throws InterruptedException { + while (true) { + Thread.sleep(1000); + // the producer is blocked once the done flag stays true + if (done.get()) { + LOG.info("Blocked...."); + break; + } + done.set(true); + } + } + + protected BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setDeleteAllMessagesOnStartup(true); + + service.setUseJmx(false); + + service.getSystemUsage().getStoreUsage().setLimit(200*1024); + + // allow destination to use 50% of store, leaving 50% for DLQ. + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setStoreUsageHighWaterMark(50); + policyMap.put(queueDest, policy); + policyMap.put(topicDest, policy); + service.setDestinationPolicy(policyMap); + + connector = service.addConnector("tcp://localhost:0"); + return service; + } + + public void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + TcpTransport t = (TcpTransport)connection.getTransport().narrow(TcpTransport.class); + t.getTransportListener().onException(new IOException("Disposed.")); + connection.getTransport().stop(); + super.tearDown(); + } + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(connector.getConnectUri()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ProducerFlowControlSendFailTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ProducerFlowControlSendFailTest.java new file mode 100644 index 0000000000..c18eccd093 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ProducerFlowControlSendFailTest.java @@ -0,0 +1,176 @@ +/** + * 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; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.ConnectionFactory; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ResourceAllocationException; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.VMPendingSubscriberMessageStoragePolicy; + +public class ProducerFlowControlSendFailTest extends ProducerFlowControlTest { + + protected BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + + // Setup a destination policy where it takes only 1 message at a time. + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setMemoryLimit(1); + policy.setPendingSubscriberPolicy(new VMPendingSubscriberMessageStoragePolicy()); + policy.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + policy.setProducerFlowControl(true); + policyMap.setDefaultEntry(policy); + service.setDestinationPolicy(policyMap); + + service.getSystemUsage().setSendFailIfNoSpace(true); + + connector = service.addConnector("tcp://localhost:0"); + return service; + } + + @Override + public void test2ndPubisherWithStandardConnectionThatIsBlocked() throws Exception { + // with sendFailIfNoSpace set, there is no blocking of the connection + } + + @Override + public void testAsyncPubisherRecoverAfterBlock() throws Exception { + // sendFail means no flowControllwindow as there is no producer ack, just an exception + } + + @Override + public void testPubisherRecoverAfterBlock() throws Exception { + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + // with sendFail, there must be no flowControllwindow + // sendFail is an alternative flow control mechanism that does not block + factory.setUseAsyncSend(true); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(queueA); + + final AtomicBoolean keepGoing = new AtomicBoolean(true); + + Thread thread = new Thread("Filler") { + @Override + public void run() { + while (keepGoing.get()) { + try { + producer.send(session.createTextMessage("Test message")); + if (gotResourceException.get()) { + // do not flood the broker with requests when full as we are sending async and they + // will be limited by the network buffers + Thread.sleep(200); + } + } catch (Exception e) { + // with async send, there will be no exceptions + e.printStackTrace(); + } + } + } + }; + thread.start(); + waitForBlockedOrResourceLimit(new AtomicBoolean(false)); + + // resourceException on second message, resumption if we + // can receive 10 + MessageConsumer consumer = session.createConsumer(queueA); + TextMessage msg; + for (int idx = 0; idx < 10; ++idx) { + msg = (TextMessage) consumer.receive(1000); + if (msg != null) { + msg.acknowledge(); + } + } + keepGoing.set(false); + } + + public void testPubisherRecoverAfterBlockWithSyncSend() throws Exception { + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + factory.setExceptionListener(null); + factory.setUseAsyncSend(false); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(queueA); + + final AtomicBoolean keepGoing = new AtomicBoolean(true); + final AtomicInteger exceptionCount = new AtomicInteger(0); + Thread thread = new Thread("Filler") { + @Override + public void run() { + while (keepGoing.get()) { + try { + producer.send(session.createTextMessage("Test message")); + } catch (JMSException arg0) { + if (arg0 instanceof ResourceAllocationException) { + gotResourceException.set(true); + exceptionCount.incrementAndGet(); + } + } + } + } + }; + thread.start(); + waitForBlockedOrResourceLimit(new AtomicBoolean(false)); + + // resourceException on second message, resumption if we + // can receive 10 + MessageConsumer consumer = session.createConsumer(queueA); + TextMessage msg; + for (int idx = 0; idx < 10; ++idx) { + msg = (TextMessage) consumer.receive(1000); + if (msg != null) { + msg.acknowledge(); + } + } + assertTrue("we were blocked at least 5 times", 5 < exceptionCount.get()); + keepGoing.set(false); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connector.getConnectUri()); + connectionFactory.setExceptionListener(new ExceptionListener() { + public void onException(JMSException arg0) { + if (arg0 instanceof ResourceAllocationException) { + gotResourceException.set(true); + } + } + }); + return connectionFactory; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ProducerFlowControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ProducerFlowControlTest.java new file mode 100644 index 0000000000..70e15eca7d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ProducerFlowControlTest.java @@ -0,0 +1,348 @@ +/** + * 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; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.VMPendingSubscriberMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.transport.tcp.TcpTransport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProducerFlowControlTest extends JmsTestSupport { + static final Logger LOG = LoggerFactory.getLogger(ProducerFlowControlTest.class); + ActiveMQQueue queueA = new ActiveMQQueue("QUEUE.A"); + ActiveMQQueue queueB = new ActiveMQQueue("QUEUE.B"); + protected TransportConnector connector; + protected ActiveMQConnection connection; + // used to test sendFailIfNoSpace on SystemUsage + protected final AtomicBoolean gotResourceException = new AtomicBoolean(false); + + public void test2ndPubisherWithProducerWindowSendConnectionThatIsBlocked() throws Exception { + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + factory.setProducerWindowSize(1024 * 64); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queueB); + + // Test sending to Queue A + // 1 few sends should not block until the producer window is used up. + fillQueue(queueA); + + // Test sending to Queue B it should not block since the connection + // should not be blocked. + CountDownLatch pubishDoneToQeueuB = asyncSendTo(queueB, "Message 1"); + assertTrue(pubishDoneToQeueuB.await(2, TimeUnit.SECONDS)); + + TextMessage msg = (TextMessage)consumer.receive(); + assertEquals("Message 1", msg.getText()); + msg.acknowledge(); + + pubishDoneToQeueuB = asyncSendTo(queueB, "Message 2"); + assertTrue(pubishDoneToQeueuB.await(2, TimeUnit.SECONDS)); + + msg = (TextMessage)consumer.receive(); + assertEquals("Message 2", msg.getText()); + msg.acknowledge(); + } + + public void testPubisherRecoverAfterBlock() throws Exception { + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(queueA); + + final AtomicBoolean done = new AtomicBoolean(true); + final AtomicBoolean keepGoing = new AtomicBoolean(true); + + + Thread thread = new Thread("Filler") { + int i; + @Override + public void run() { + while (keepGoing.get()) { + done.set(false); + try { + producer.send(session.createTextMessage("Test message " + ++i)); + LOG.info("sent: " + i); + } catch (JMSException e) { + } + } + } + }; + thread.start(); + waitForBlockedOrResourceLimit(done); + + // after receiveing messges, producer should continue sending messages + // (done == false) + MessageConsumer consumer = session.createConsumer(queueA); + TextMessage msg; + for (int idx = 0; idx < 5; ++idx) { + msg = (TextMessage) consumer.receive(1000); + LOG.info("received: " + idx + ", msg: " + msg.getJMSMessageID()); + msg.acknowledge(); + } + Thread.sleep(1000); + keepGoing.set(false); + + assertFalse("producer has resumed", done.get()); + } + + public void testAsyncPubisherRecoverAfterBlock() throws Exception { + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + factory.setProducerWindowSize(1024 * 5); + factory.setUseAsyncSend(true); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(queueA); + + final AtomicBoolean done = new AtomicBoolean(true); + final AtomicBoolean keepGoing = new AtomicBoolean(true); + + + Thread thread = new Thread("Filler") { + int i; + @Override + public void run() { + while (keepGoing.get()) { + done.set(false); + try { + producer.send(session.createTextMessage("Test message " + ++i)); + LOG.info("sent: " + i); + } catch (JMSException e) { + } + } + } + }; + thread.start(); + waitForBlockedOrResourceLimit(done); + + // after receiveing messges, producer should continue sending messages + // (done == false) + MessageConsumer consumer = session.createConsumer(queueA); + TextMessage msg; + for (int idx = 0; idx < 5; ++idx) { + msg = (TextMessage) consumer.receive(1000); + assertNotNull("Got a message", msg); + LOG.info("received: " + idx + ", msg: " + msg.getJMSMessageID()); + msg.acknowledge(); + } + Thread.sleep(1000); + keepGoing.set(false); + + assertFalse("producer has resumed", done.get()); + } + + public void test2ndPubisherWithSyncSendConnectionThatIsBlocked() throws Exception { + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + factory.setAlwaysSyncSend(true); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queueB); + + // Test sending to Queue A + // 1st send should not block. But the rest will. + fillQueue(queueA); + + // Test sending to Queue B it should not block. + CountDownLatch pubishDoneToQeueuB = asyncSendTo(queueB, "Message 1"); + assertTrue(pubishDoneToQeueuB.await(2, TimeUnit.SECONDS)); + + TextMessage msg = (TextMessage)consumer.receive(); + assertEquals("Message 1", msg.getText()); + msg.acknowledge(); + + pubishDoneToQeueuB = asyncSendTo(queueB, "Message 2"); + assertTrue(pubishDoneToQeueuB.await(2, TimeUnit.SECONDS)); + + msg = (TextMessage)consumer.receive(); + assertEquals("Message 2", msg.getText()); + msg.acknowledge(); + } + + public void testSimpleSendReceive() throws Exception { + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + factory.setAlwaysSyncSend(true); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queueA); + + // Test sending to Queue B it should not block. + CountDownLatch pubishDoneToQeueuA = asyncSendTo(queueA, "Message 1"); + assertTrue(pubishDoneToQeueuA.await(2, TimeUnit.SECONDS)); + + TextMessage msg = (TextMessage)consumer.receive(); + assertEquals("Message 1", msg.getText()); + msg.acknowledge(); + + pubishDoneToQeueuA = asyncSendTo(queueA, "Message 2"); + assertTrue(pubishDoneToQeueuA.await(2, TimeUnit.SECONDS)); + + msg = (TextMessage)consumer.receive(); + assertEquals("Message 2", msg.getText()); + msg.acknowledge(); + } + + public void test2ndPubisherWithStandardConnectionThatIsBlocked() throws Exception { + ConnectionFactory factory = createConnectionFactory(); + connection = (ActiveMQConnection)factory.createConnection(); + connections.add(connection); + connection.start(); + + // Test sending to Queue A + // 1st send should not block. + fillQueue(queueA); + + // Test sending to Queue B it should block. + // Since even though the it's queue limits have not been reached, the + // connection + // is blocked. + CountDownLatch pubishDoneToQeueuB = asyncSendTo(queueB, "Message 1"); + assertFalse(pubishDoneToQeueuB.await(2, TimeUnit.SECONDS)); + } + + private void fillQueue(final ActiveMQQueue queue) throws JMSException, InterruptedException { + final AtomicBoolean done = new AtomicBoolean(true); + final AtomicBoolean keepGoing = new AtomicBoolean(true); + + // Starts an async thread that every time it publishes it sets the done + // flag to false. + // Once the send starts to block it will not reset the done flag + // anymore. + new Thread("Fill thread.") { + public void run() { + Session session = null; + try { + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + while (keepGoing.get()) { + done.set(false); + producer.send(session.createTextMessage("Hello World")); + } + } catch (JMSException e) { + } finally { + safeClose(session); + } + } + }.start(); + + waitForBlockedOrResourceLimit(done); + keepGoing.set(false); + } + + protected void waitForBlockedOrResourceLimit(final AtomicBoolean done) + throws InterruptedException { + while (true) { + Thread.sleep(1000); + // the producer is blocked once the done flag stays true or there is a resource exception + if (done.get() || gotResourceException.get()) { + break; + } + done.set(true); + } + } + + private CountDownLatch asyncSendTo(final ActiveMQQueue queue, final String message) throws JMSException { + final CountDownLatch done = new CountDownLatch(1); + new Thread("Send thread.") { + public void run() { + Session session = null; + try { + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(session.createTextMessage(message)); + done.countDown(); + } catch (JMSException e) { + } finally { + safeClose(session); + } + } + }.start(); + return done; + } + + protected BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + + // Setup a destination policy where it takes only 1 message at a time. + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setMemoryLimit(1); + policy.setPendingSubscriberPolicy(new VMPendingSubscriberMessageStoragePolicy()); + policy.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + policy.setProducerFlowControl(true); + policyMap.setDefaultEntry(policy); + service.setDestinationPolicy(policyMap); + + connector = service.addConnector("tcp://localhost:0"); + return service; + } + + public void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + TcpTransport t = (TcpTransport)connection.getTransport().narrow(TcpTransport.class); + t.getTransportListener().onException(new IOException("Disposed.")); + connection.getTransport().stop(); + } + super.tearDown(); + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(connector.getConnectUri()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/QueueConsumerPriorityTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/QueueConsumerPriorityTest.java new file mode 100644 index 0000000000..2a61820cc3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/QueueConsumerPriorityTest.java @@ -0,0 +1,94 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQQueue; + +public class QueueConsumerPriorityTest extends TestCase { + + private static final String VM_BROKER_URL = "vm://localhost?broker.persistent=false&broker.useJmx=true"; + + public QueueConsumerPriorityTest(String name) { + super(name); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + private Connection createConnection(final boolean start) throws JMSException { + ConnectionFactory cf = new ActiveMQConnectionFactory(VM_BROKER_URL); + Connection conn = cf.createConnection(); + if (start) { + conn.start(); + } + return conn; + } + + public void testQueueConsumerPriority() throws JMSException, InterruptedException { + Connection conn = createConnection(true); + + Session consumerLowPriority = null; + Session consumerHighPriority = null; + Session senderSession = null; + + try { + + consumerLowPriority = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerHighPriority = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + assertNotNull(consumerHighPriority); + senderSession = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + String queueName = getClass().getName(); + ActiveMQQueue low = new ActiveMQQueue(queueName+"?consumer.priority=1"); + MessageConsumer lowConsumer = consumerLowPriority.createConsumer(low); + + ActiveMQQueue high = new ActiveMQQueue(queueName+"?consumer.priority=2"); + MessageConsumer highConsumer = consumerLowPriority.createConsumer(high); + + ActiveMQQueue senderQueue = new ActiveMQQueue(queueName); + + MessageProducer producer = senderSession.createProducer(senderQueue); + + Message msg = senderSession.createTextMessage("test"); + for (int i =0; i< 10000;i++) { + producer.send(msg); + assertNotNull("null on iteration: " + i, highConsumer.receive(500)); + } + assertNull(lowConsumer.receive(2000)); + + } finally { + conn.close(); + } + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ReconnectWithSameClientIDTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ReconnectWithSameClientIDTest.java new file mode 100644 index 0000000000..81d13b2f1e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ReconnectWithSameClientIDTest.java @@ -0,0 +1,116 @@ +/** + * 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; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.InvalidClientIDException; +import javax.jms.JMSException; +import javax.jms.Session; + +import junit.framework.Test; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.spi.LoggingEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReconnectWithSameClientIDTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ReconnectWithSameClientIDTest.class); + + protected Connection connection; + protected boolean transacted; + protected int authMode = Session.AUTO_ACKNOWLEDGE; + public boolean useFailover = false; + + public static Test suite() { + return suite(ReconnectWithSameClientIDTest.class); + } + + public void initCombosForTestReconnectMultipleTimesWithSameClientID() { + addCombinationValues("useFailover", new Object[]{Boolean.FALSE, Boolean.TRUE}); + } + + public void testReconnectMultipleTimesWithSameClientID() throws Exception { + + org.apache.log4j.Logger log4jLogger = + org.apache.log4j.Logger.getLogger(org.apache.activemq.broker.jmx.ManagedTransportConnection.class); + final AtomicBoolean failed = new AtomicBoolean(false); + + Appender appender = new DefaultTestAppender() { + @Override + public void doAppend(LoggingEvent event) { + if (event.getMessage().toString().startsWith("Failed to register MBean")) { + LOG.info("received unexpected log message: " + event.getMessage()); + failed.set(true); + } + } + }; + log4jLogger.addAppender(appender); + try { + connection = connectionFactory.createConnection(); + useConnection(connection); + + // now lets create another which should fail + for (int i = 1; i < 11; i++) { + Connection connection2 = connectionFactory.createConnection(); + try { + useConnection(connection2); + fail("Should have thrown InvalidClientIDException on attempt" + i); + } catch (InvalidClientIDException e) { + LOG.info("Caught expected: " + e); + } finally { + connection2.close(); + } + } + + // now lets try closing the original connection and creating a new + // connection with the same ID + connection.close(); + connection = connectionFactory.createConnection(); + useConnection(connection); + } finally { + log4jLogger.removeAppender(appender); + } + assertFalse("failed on unexpected log event", failed.get()); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory((useFailover ? "failover:" : "") + + broker.getTransportConnectors().get(0).getPublishableConnectString()); + } + + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + super.setUp(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + protected void useConnection(Connection connection) throws JMSException { + connection.setClientID("foo"); + connection.start(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/RedeliveryPolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/RedeliveryPolicyTest.java new file mode 100644 index 0000000000..e2b58677c3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/RedeliveryPolicyTest.java @@ -0,0 +1,830 @@ +/** + * 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; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.ServerSession; +import javax.jms.ServerSessionPool; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.Test; + +import org.apache.activemq.broker.region.policy.RedeliveryPolicyMap; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; + +public class RedeliveryPolicyTest extends JmsTestSupport { + + public static Test suite() { + return suite(RedeliveryPolicyTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + + public void testGetNext() throws Exception { + + RedeliveryPolicy policy = new RedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setRedeliveryDelay(500); + policy.setBackOffMultiplier((short) 2); + policy.setUseExponentialBackOff(true); + + long delay = policy.getNextRedeliveryDelay(0); + assertEquals(500, delay); + delay = policy.getNextRedeliveryDelay(delay); + assertEquals(500*2, delay); + delay = policy.getNextRedeliveryDelay(delay); + assertEquals(500*4, delay); + + policy.setUseExponentialBackOff(false); + delay = policy.getNextRedeliveryDelay(delay); + assertEquals(500, delay); + } + + /** + * @throws Exception + */ + public void testExponentialRedeliveryPolicyDelaysDeliveryOnRollback() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setRedeliveryDelay(500); + policy.setBackOffMultiplier((short) 2); + policy.setUseExponentialBackOff(true); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue(getName()); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + // No delay on first rollback.. + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + session.rollback(); + + // Show subsequent re-delivery delay is incrementing. + m = (TextMessage)consumer.receive(100); + assertNull(m); + + m = (TextMessage)consumer.receive(700); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + // Show re-delivery delay is incrementing exponentially + m = (TextMessage)consumer.receive(100); + assertNull(m); + m = (TextMessage)consumer.receive(500); + assertNull(m); + m = (TextMessage)consumer.receive(700); + assertNotNull(m); + assertEquals("1st", m.getText()); + + } + + + /** + * @throws Exception + */ + public void testNornalRedeliveryPolicyDelaysDeliveryOnRollback() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setRedeliveryDelay(500); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue(getName()); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + // No delay on first rollback.. + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + session.rollback(); + + // Show subsequent re-delivery delay is incrementing. + m = (TextMessage)consumer.receive(100); + assertNull(m); + m = (TextMessage)consumer.receive(700); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + // The message gets redelivered after 500 ms every time since + // we are not using exponential backoff. + m = (TextMessage)consumer.receive(100); + assertNull(m); + m = (TextMessage)consumer.receive(700); + assertNotNull(m); + assertEquals("1st", m.getText()); + + } + + /** + * @throws Exception + */ + public void testDLQHandling() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(100); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(2); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + MessageConsumer dlqConsumer = session.createConsumer(new ActiveMQQueue("ActiveMQ.DLQ")); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + // The last rollback should cause the 1st message to get sent to the DLQ + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + + // We should be able to get the message off the DLQ now. + m = (TextMessage)dlqConsumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + String cause = m.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); + assertTrue("cause exception has policy ref", cause.contains("RedeliveryPolicy")); + session.commit(); + + } + + + /** + * @throws Exception + */ + public void testInfiniteMaximumNumberOfRedeliveries() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(100); + policy.setUseExponentialBackOff(false); + // let's set the maximum redeliveries to no maximum (ie. infinite) + policy.setMaximumRedeliveries(-1); + + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + //we should be able to get the 1st message redelivered until a session.commit is called + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.commit(); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + + } + + /** + * @throws Exception + */ + public void testMaximumRedeliveryDelay() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(10); + policy.setUseExponentialBackOff(true); + policy.setMaximumRedeliveries(-1); + policy.setRedeliveryDelay(50); + policy.setMaximumRedeliveryDelay(1000); + policy.setBackOffMultiplier((short) 2); + policy.setUseExponentialBackOff(true); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + + for(int i = 0; i < 10; ++i) { + // we should be able to get the 1st message redelivered until a session.commit is called + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + } + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.commit(); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + + assertTrue(policy.getNextRedeliveryDelay(Long.MAX_VALUE) == 1000 ); + } + + /** + * @throws Exception + */ + public void testZeroMaximumNumberOfRedeliveries() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(100); + policy.setUseExponentialBackOff(false); + //let's set the maximum redeliveries to 0 + policy.setMaximumRedeliveries(0); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + //the 1st message should not be redelivered since maximumRedeliveries is set to 0 + m = (TextMessage)consumer.receive(1000); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + + + + } + + public void testRepeatedRedeliveryReceiveNoCommit() throws Exception { + + connection.start(); + Session dlqSession = connection.createSession(true, Session.SESSION_TRANSACTED); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = dlqSession.createProducer(destination); + + // Send the messages + producer.send(dlqSession.createTextMessage("1st")); + + dlqSession.commit(); + MessageConsumer dlqConsumer = dlqSession.createConsumer(new ActiveMQQueue("ActiveMQ.DLQ")); + + final int maxRedeliveries = 4; + for (int i=0;i<=maxRedeliveries +1;i++) { + + connection = (ActiveMQConnection)factory.createConnection(userName, password); + connections.add(connection); + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(maxRedeliveries); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + + ActiveMQTextMessage m = ((ActiveMQTextMessage)consumer.receive(4000)); + if (i<=maxRedeliveries) { + assertEquals("1st", m.getText()); + assertEquals(i, m.getRedeliveryCounter()); + } else { + assertNull("null on exceeding redelivery count", m); + } + connection.close(); + connections.remove(connection); + } + + // We should be able to get the message off the DLQ now. + TextMessage m = (TextMessage)dlqConsumer.receive(1000); + assertNotNull("Got message from DLQ", m); + assertEquals("1st", m.getText()); + String cause = m.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); + assertTrue("cause exception has policy ref", cause.contains("RedeliveryPolicy")); + dlqSession.commit(); + + } + + + public void testRepeatedRedeliveryOnMessageNoCommit() throws Exception { + + connection.start(); + Session dlqSession = connection.createSession(true, Session.SESSION_TRANSACTED); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = dlqSession.createProducer(destination); + + // Send the messages + producer.send(dlqSession.createTextMessage("1st")); + + dlqSession.commit(); + MessageConsumer dlqConsumer = dlqSession.createConsumer(new ActiveMQQueue("ActiveMQ.DLQ")); + + final int maxRedeliveries = 4; + final AtomicInteger receivedCount = new AtomicInteger(0); + + for (int i=0;i<=maxRedeliveries+1;i++) { + + connection = (ActiveMQConnection)factory.createConnection(userName, password); + connections.add(connection); + + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(maxRedeliveries); + + connection.start(); + final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(destination); + final CountDownLatch done = new CountDownLatch(1); + + consumer.setMessageListener(new MessageListener(){ + @Override + public void onMessage(Message message) { + try { + ActiveMQTextMessage m = (ActiveMQTextMessage)message; + assertEquals("1st", m.getText()); + assertEquals(receivedCount.get(), m.getRedeliveryCounter()); + receivedCount.incrementAndGet(); + done.countDown(); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + }); + + if (i<=maxRedeliveries) { + assertTrue("listener done", done.await(5, TimeUnit.SECONDS)); + } else { + // final redlivery gets poisoned before dispatch + assertFalse("listener done", done.await(1, TimeUnit.SECONDS)); + } + connection.close(); + connections.remove(connection); + } + + // We should be able to get the message off the DLQ now. + TextMessage m = (TextMessage)dlqConsumer.receive(1000); + assertNotNull("Got message from DLQ", m); + assertEquals("1st", m.getText()); + String cause = m.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); + assertTrue("cause exception has policy ref", cause.contains("RedeliveryPolicy")); + dlqSession.commit(); + + } + + public void testRepeatedRedeliveryServerSessionNoCommit() throws Exception { + + connection.start(); + Session dlqSession = connection.createSession(true, Session.SESSION_TRANSACTED); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = dlqSession.createProducer(destination); + + // Send the messages + producer.send(dlqSession.createTextMessage("1st")); + + dlqSession.commit(); + MessageConsumer dlqConsumer = dlqSession.createConsumer(new ActiveMQQueue("ActiveMQ.DLQ")); + + final int maxRedeliveries = 4; + final AtomicInteger receivedCount = new AtomicInteger(0); + + for (int i=0;i<=maxRedeliveries+1;i++) { + + connection = (ActiveMQConnection)factory.createConnection(userName, password); + connections.add(connection); + + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(maxRedeliveries); + + connection.start(); + final CountDownLatch done = new CountDownLatch(1); + + final ActiveMQSession session = (ActiveMQSession) connection.createSession(true, Session.SESSION_TRANSACTED); + session.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + ActiveMQTextMessage m = (ActiveMQTextMessage) message; + assertEquals("1st", m.getText()); + assertEquals(receivedCount.get(), m.getRedeliveryCounter()); + receivedCount.incrementAndGet(); + done.countDown(); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + }); + + connection.createConnectionConsumer( + destination, + null, + new ServerSessionPool() { + @Override + public ServerSession getServerSession() throws JMSException { + return new ServerSession() { + @Override + public Session getSession() throws JMSException { + return session; + } + + @Override + public void start() throws JMSException { + } + }; + } + }, + 100, + false); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + session.run(); + return done.await(10, TimeUnit.MILLISECONDS); + } + }); + + if (i<=maxRedeliveries) { + assertTrue("listener done @" + i, done.await(5, TimeUnit.SECONDS)); + } else { + // final redlivery gets poisoned before dispatch + assertFalse("listener not done @" + i, done.await(1, TimeUnit.SECONDS)); + } + connection.close(); + connections.remove(connection); + } + + // We should be able to get the message off the DLQ now. + TextMessage m = (TextMessage)dlqConsumer.receive(1000); + assertNotNull("Got message from DLQ", m); + assertEquals("1st", m.getText()); + String cause = m.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); + assertTrue("cause exception has policy ref", cause.contains("RedeliveryPolicy")); + dlqSession.commit(); + + } + + public void testInitialRedeliveryDelayZero() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(1); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + assertEquals("1st", m.getText()); + + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + + session.commit(); + } + + + public void testInitialRedeliveryDelayOne() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(1000); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(1); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(100); + assertNull(m); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + } + + public void testRedeliveryDelayOne() throws Exception { + + // Receive a message with the JMS API + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(0); + policy.setRedeliveryDelay(1000); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(2); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + // Send the messages + producer.send(session.createTextMessage("1st")); + producer.send(session.createTextMessage("2nd")); + session.commit(); + + TextMessage m; + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + assertEquals("1st", m.getText()); + session.rollback(); + + m = (TextMessage)consumer.receive(100); + assertNotNull("first immediate redelivery", m); + session.rollback(); + + m = (TextMessage)consumer.receive(100); + assertNull("second delivery delayed: " + m, m); + + m = (TextMessage)consumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + + m = (TextMessage)consumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + } + + public void testRedeliveryPolicyPerDestination() throws Exception { + + RedeliveryPolicy queuePolicy = new RedeliveryPolicy(); + queuePolicy.setInitialRedeliveryDelay(0); + queuePolicy.setRedeliveryDelay(1000); + queuePolicy.setUseExponentialBackOff(false); + queuePolicy.setMaximumRedeliveries(2); + + RedeliveryPolicy topicPolicy = new RedeliveryPolicy(); + topicPolicy.setInitialRedeliveryDelay(0); + topicPolicy.setRedeliveryDelay(1000); + topicPolicy.setUseExponentialBackOff(false); + topicPolicy.setMaximumRedeliveries(3); + + // Receive a message with the JMS API + RedeliveryPolicyMap map = connection.getRedeliveryPolicyMap(); + map.put(new ActiveMQTopic(">"), topicPolicy); + map.put(new ActiveMQQueue(">"), queuePolicy); + + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + ActiveMQTopic topic = new ActiveMQTopic("TEST"); + + MessageProducer producer = session.createProducer(null); + + MessageConsumer queueConsumer = session.createConsumer(queue); + MessageConsumer topicConsumer = session.createConsumer(topic); + + // Send the messages + producer.send(queue, session.createTextMessage("1st")); + producer.send(queue, session.createTextMessage("2nd")); + producer.send(topic, session.createTextMessage("1st")); + producer.send(topic, session.createTextMessage("2nd")); + + session.commit(); + + TextMessage m; + m = (TextMessage)queueConsumer.receive(100); + assertNotNull(m); + assertEquals("1st", m.getText()); + m = (TextMessage)topicConsumer.receive(100); + assertNotNull(m); + assertEquals("1st", m.getText()); + m = (TextMessage)queueConsumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + m = (TextMessage)topicConsumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.rollback(); + + m = (TextMessage)queueConsumer.receive(100); + assertNotNull("first immediate redelivery", m); + m = (TextMessage)topicConsumer.receive(100); + assertNotNull("first immediate redelivery", m); + session.rollback(); + + m = (TextMessage)queueConsumer.receive(100); + assertNull("second delivery delayed: " + m, m); + m = (TextMessage)topicConsumer.receive(100); + assertNull("second delivery delayed: " + m, m); + + m = (TextMessage)queueConsumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + m = (TextMessage)topicConsumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + + m = (TextMessage)queueConsumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + m = (TextMessage)topicConsumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.rollback(); + + m = (TextMessage)queueConsumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + m = (TextMessage)topicConsumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + + m = (TextMessage)queueConsumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + m = (TextMessage)topicConsumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.rollback(); + + // No third attempt for the Queue consumer + m = (TextMessage)queueConsumer.receive(2000); + assertNull(m); + m = (TextMessage)topicConsumer.receive(2000); + assertNotNull(m); + assertEquals("1st", m.getText()); + + m = (TextMessage)queueConsumer.receive(100); + assertNull(m); + m = (TextMessage)topicConsumer.receive(100); + assertNotNull(m); + assertEquals("2nd", m.getText()); + session.commit(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/RemoveDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/RemoveDestinationTest.java new file mode 100644 index 0000000000..009221b53f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/RemoveDestinationTest.java @@ -0,0 +1,165 @@ +/** + * 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; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.management.ObjectName; + +import org.apache.activemq.advisory.DestinationSource; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class RemoveDestinationTest { + + private static final String VM_BROKER_URL = "vm://localhost?create=false"; + private static final String BROKER_URL = "broker:vm://localhost?broker.persistent=false&broker.useJmx=true"; + + BrokerService broker; + + @Before + public void setUp() throws Exception { + broker = BrokerFactory.createBroker(new URI(BROKER_URL)); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + + private Connection createConnection(final boolean start) throws JMSException { + ConnectionFactory cf = new ActiveMQConnectionFactory(VM_BROKER_URL); + Connection conn = cf.createConnection(); + if (start) { + conn.start(); + } + return conn; + } + + @Test + public void testRemoveDestinationWithoutSubscriber() throws Exception { + + ActiveMQConnection amqConnection = (ActiveMQConnection) createConnection(true); + DestinationSource destinationSource = amqConnection.getDestinationSource(); + Session session = amqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TEST.FOO"); + MessageProducer producer = session.createProducer(topic); + MessageConsumer consumer = session.createConsumer(topic); + + TextMessage msg = session.createTextMessage("Hellow World"); + producer.send(msg); + assertNotNull(consumer.receive(5000)); + Thread.sleep(1000); + + ActiveMQTopic amqTopic = (ActiveMQTopic) topic; + assertTrue(destinationSource.getTopics().contains(amqTopic)); + + consumer.close(); + producer.close(); + session.close(); + + Thread.sleep(3000); + amqConnection.destroyDestination((ActiveMQDestination) topic); + Thread.sleep(3000); + assertFalse(destinationSource.getTopics().contains(amqTopic)); + } + + @Test + public void testRemoveDestinationWithSubscriber() throws Exception { + ActiveMQConnection amqConnection = (ActiveMQConnection) createConnection(true); + DestinationSource destinationSource = amqConnection.getDestinationSource(); + + Session session = amqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TEST.FOO"); + MessageProducer producer = session.createProducer(topic); + MessageConsumer consumer = session.createConsumer(topic); + + TextMessage msg = session.createTextMessage("Hellow World"); + producer.send(msg); + assertNotNull(consumer.receive(5000)); + Thread.sleep(1000); + + ActiveMQTopic amqTopic = (ActiveMQTopic) topic; + + assertTrue(destinationPresentInAdminView(broker, amqTopic)); + assertTrue(destinationSource.getTopics().contains(amqTopic)); + + // This line generates a broker error since the consumer is still active. + try { + amqConnection.destroyDestination((ActiveMQDestination) topic); + fail("expect exception on destroy if comsumer present"); + } catch (JMSException expected) { + assertTrue(expected.getMessage().indexOf(amqTopic.getTopicName()) != -1); + } + + Thread.sleep(3000); + + assertTrue(destinationSource.getTopics().contains(amqTopic)); + assertTrue(destinationPresentInAdminView(broker, amqTopic)); + + consumer.close(); + producer.close(); + session.close(); + + Thread.sleep(3000); + + // The destination will not be removed with this call, but if you remove + // the call above that generates the error it will. + amqConnection.destroyDestination(amqTopic); + Thread.sleep(3000); + assertFalse(destinationSource.getTopics().contains(amqTopic)); + assertFalse(destinationPresentInAdminView(broker, amqTopic)); + } + + private boolean destinationPresentInAdminView(BrokerService broker2, ActiveMQTopic amqTopic) throws Exception { + boolean found = false; + for (ObjectName name : broker.getAdminView().getTopics()) { + + DestinationViewMBean proxy = (DestinationViewMBean) + broker.getManagementContext().newProxyInstance(name, DestinationViewMBean.class, true); + + if (proxy.getName().equals(amqTopic.getPhysicalName())) { + found = true; + break; + } + } + return found; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/SpringTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/SpringTestSupport.java new file mode 100644 index 0000000000..f713120139 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/SpringTestSupport.java @@ -0,0 +1,65 @@ +/** + * 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; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.context.support.AbstractApplicationContext; + +/** + * A useful base class for spring based unit test cases + * + * + */ +public abstract class SpringTestSupport extends TestCase { + + protected AbstractApplicationContext context; + + @Override + protected void setUp() throws Exception { + context = createApplicationContext(); + } + + protected abstract AbstractApplicationContext createApplicationContext();; + + @Override + protected void tearDown() throws Exception { + if (context != null) { + context.destroy(); + } + } + + protected Object getBean(String name) { + Object bean = context.getBean(name); + if (bean == null) { + fail("Should have found bean named '" + name + "' in the Spring ApplicationContext"); + } + return bean; + } + + protected void assertSetEquals(String description, Object[] expected, Set actual) { + Set expectedSet = new HashSet(); + expectedSet.addAll(Arrays.asList(expected)); + assertEquals(description, expectedSet, actual); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TestSupport.java new file mode 100644 index 0000000000..a762f89f6a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TestSupport.java @@ -0,0 +1,228 @@ +/** + * 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; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.TextMessage; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.leveldb.LevelDBPersistenceAdapter; +import org.apache.activemq.store.memory.MemoryPersistenceAdapter; + +/** + * Useful base class for unit test cases + * + * + */ +public abstract class TestSupport extends CombinationTestSupport { + + protected ActiveMQConnectionFactory connectionFactory; + protected boolean topic = true; + public PersistenceAdapterChoice defaultPersistenceAdapter = PersistenceAdapterChoice.KahaDB; + + protected ActiveMQMessage createMessage() { + return new ActiveMQMessage(); + } + + protected Destination createDestination(String subject) { + if (topic) { + return new ActiveMQTopic(subject); + } else { + return new ActiveMQQueue(subject); + } + } + + protected Destination createDestination() { + return createDestination(getDestinationString()); + } + + /** + * Returns the name of the destination used in this test case + */ + protected String getDestinationString() { + return getClass().getName() + "." + getName(true); + } + + /** + * @param messsage + * @param firstSet + * @param secondSet + */ + protected void assertTextMessagesEqual(String messsage, Message[] firstSet, Message[] secondSet) + throws JMSException { + assertEquals("Message count does not match: " + messsage, firstSet.length, secondSet.length); + for (int i = 0; i < secondSet.length; i++) { + TextMessage m1 = (TextMessage)firstSet[i]; + TextMessage m2 = (TextMessage)secondSet[i]; + assertFalse("Message " + (i + 1) + " did not match : " + messsage + ": expected {" + m1 + + "}, but was {" + m2 + "}", m1 == null ^ m2 == null); + assertEquals("Message " + (i + 1) + " did not match: " + messsage + ": expected {" + m1 + + "}, but was {" + m2 + "}", m1.getText(), m2.getText()); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + } + + /** + * Factory method to create a new connection + */ + protected Connection createConnection() throws Exception { + return getConnectionFactory().createConnection(); + } + + public ActiveMQConnectionFactory getConnectionFactory() throws Exception { + if (connectionFactory == null) { + connectionFactory = createConnectionFactory(); + assertTrue("Should have created a connection factory!", connectionFactory != null); + } + return connectionFactory; + } + + protected String getConsumerSubject() { + return getSubject(); + } + + protected String getProducerSubject() { + return getSubject(); + } + + protected String getSubject() { + return getName(); + } + + public static void recursiveDelete(File f) { + if (f.isDirectory()) { + File[] files = f.listFiles(); + for (int i = 0; i < files.length; i++) { + recursiveDelete(files[i]); + } + } + f.delete(); + } + + public static void removeMessageStore() { + if (System.getProperty("activemq.store.dir") != null) { + recursiveDelete(new File(System.getProperty("activemq.store.dir"))); + } + if (System.getProperty("derby.system.home") != null) { + recursiveDelete(new File(System.getProperty("derby.system.home"))); + } + } + + public static DestinationStatistics getDestinationStatistics(BrokerService broker, ActiveMQDestination destination) { + DestinationStatistics result = null; + org.apache.activemq.broker.region.Destination dest = getDestination(broker, destination); + if (dest != null) { + result = dest.getDestinationStatistics(); + } + return result; + } + + public static org.apache.activemq.broker.region.Destination getDestination(BrokerService target, ActiveMQDestination destination) { + org.apache.activemq.broker.region.Destination result = null; + for (org.apache.activemq.broker.region.Destination dest : getDestinationMap(target, destination).values()) { + if (dest.getName().equals(destination.getPhysicalName())) { + result = dest; + break; + } + } + return result; + } + + private static Map getDestinationMap(BrokerService target, + ActiveMQDestination destination) { + RegionBroker regionBroker = (RegionBroker) target.getRegionBroker(); + if (destination.isTemporary()) { + return destination.isQueue() ? regionBroker.getTempQueueRegion().getDestinationMap() : + regionBroker.getTempTopicRegion().getDestinationMap(); + } + return destination.isQueue() ? + regionBroker.getQueueRegion().getDestinationMap() : + regionBroker.getTopicRegion().getDestinationMap(); + } + + public static enum PersistenceAdapterChoice {LevelDB, KahaDB, AMQ, JDBC, MEM }; + + public PersistenceAdapter setDefaultPersistenceAdapter(BrokerService broker) throws IOException { + return setPersistenceAdapter(broker, defaultPersistenceAdapter); + } + + public static PersistenceAdapter setPersistenceAdapter(BrokerService broker, PersistenceAdapterChoice choice) throws IOException { + PersistenceAdapter adapter = null; + switch (choice) { + case JDBC: + JDBCPersistenceAdapter jdbcPersistenceAdapter = new JDBCPersistenceAdapter(); + jdbcPersistenceAdapter.setUseLock(false); // rollback (at shutdown) on derby can take a long time with file io etc + adapter = jdbcPersistenceAdapter; + break; + case KahaDB: + adapter = new KahaDBPersistenceAdapter(); + break; + case LevelDB: + adapter = new LevelDBPersistenceAdapter(); + break; + case MEM: + adapter = new MemoryPersistenceAdapter(); + break; + } + broker.setPersistenceAdapter(adapter); + adapter.setDirectory(new File(broker.getBrokerDataDirectory(), choice.name())); + return adapter; + } + + public void stopBrokerWithStoreFailure(BrokerService broker, PersistenceAdapterChoice choice) throws Exception { + switch (choice) { + case KahaDB: + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + + // have the broker stop with an IOException on next checkpoint so it has a pending local transaction to recover + kahaDBPersistenceAdapter.getStore().getJournal().close(); + break; + default: + // just stop normally by default + broker.stop(); + } + broker.waitUntilStopped(); + } + + + /** + * Test if base directory contains spaces + */ + protected void assertBaseDirectoryContainsSpaces() { + assertFalse("Base directory cannot contain spaces.", new File(System.getProperty("basedir", ".")).getAbsoluteFile().toString().contains(" ")); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TimeStampTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TimeStampTest.java new file mode 100644 index 0000000000..2ec57b5aaf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TimeStampTest.java @@ -0,0 +1,97 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.util.UDPTraceBrokerPlugin; +import org.apache.activemq.broker.view.ConnectionDotFilePlugin; + +public class TimeStampTest extends TestCase { + public void test() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.setPlugins(new BrokerPlugin[] {new ConnectionDotFilePlugin(), new UDPTraceBrokerPlugin()}); + TransportConnector tcpConnector = broker.addConnector("tcp://localhost:0"); + broker.addConnector("stomp://localhost:0"); + broker.start(); + + // Create a ConnectionFactory + ActiveMQConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(tcpConnector.getConnectUri()); + + // Create a Connection + Connection connection = connectionFactory.createConnection(); + connection.start(); + + // Create a Session + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the destination Queue + Destination destination = session.createQueue("TEST.FOO"); + + // Create a MessageProducer from the Session to the Topic or Queue + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + // Create a messages + Message sentMessage = session.createMessage(); + + // Tell the producer to send the message + long beforeSend = System.currentTimeMillis(); + producer.send(sentMessage); + long afterSend = System.currentTimeMillis(); + + // assert message timestamp is in window + assertTrue(beforeSend <= sentMessage.getJMSTimestamp() && sentMessage.getJMSTimestamp() <= afterSend); + + // Create a MessageConsumer from the Session to the Topic or Queue + MessageConsumer consumer = session.createConsumer(destination); + + // Wait for a message + Message receivedMessage = consumer.receive(1000); + + // assert we got the same message ID we sent + assertEquals(sentMessage.getJMSMessageID(), receivedMessage.getJMSMessageID()); + + // assert message timestamp is in window + assertTrue("JMS Message Timestamp should be set during the send method: \n" + " beforeSend = " + beforeSend + "\n" + " getJMSTimestamp = " + + receivedMessage.getJMSTimestamp() + "\n" + " afterSend = " + afterSend + "\n", beforeSend <= receivedMessage.getJMSTimestamp() + && receivedMessage.getJMSTimestamp() <= afterSend); + + // assert message timestamp is unchanged + assertEquals("JMS Message Timestamp of recieved message should be the same as the sent message\n ", sentMessage.getJMSTimestamp(), receivedMessage.getJMSTimestamp()); + + // Clean up + producer.close(); + consumer.close(); + session.close(); + connection.close(); + broker.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TransactionContextTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TransactionContextTest.java new file mode 100644 index 0000000000..5e45d522e8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/TransactionContextTest.java @@ -0,0 +1,140 @@ +/** + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.TransactionRolledBackException; + +import org.apache.activemq.transaction.Synchronization; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TransactionContextTest { + + TransactionContext underTest; + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + ActiveMQConnection connection; + + + @Before + public void setup() throws Exception { + connection = factory.createActiveMQConnection(); + underTest = new TransactionContext(connection); + } + + @After + public void tearDown() throws Exception { + connection.close(); + } + + @Test + public void testSyncBeforeEndCalledOnceOnRollback() throws Exception { + final AtomicInteger beforeEndCountA = new AtomicInteger(0); + final AtomicInteger beforeEndCountB = new AtomicInteger(0); + final AtomicInteger rollbackCountA = new AtomicInteger(0); + final AtomicInteger rollbackCountB = new AtomicInteger(0); + underTest.addSynchronization(new Synchronization() { + @Override + public void beforeEnd() throws Exception { + if (beforeEndCountA.getAndIncrement() == 0) { + throw new TransactionRolledBackException("force rollback"); + } + } + + @Override + public void afterCommit() throws Exception { + fail("exepcted rollback exception"); + } + + @Override + public void afterRollback() throws Exception { + rollbackCountA.incrementAndGet(); + } + + }); + + underTest.addSynchronization(new Synchronization() { + @Override + public void beforeEnd() throws Exception { + beforeEndCountB.getAndIncrement(); + } + + @Override + public void afterCommit() throws Exception { + fail("exepcted rollback exception"); + } + + @Override + public void afterRollback() throws Exception { + rollbackCountB.incrementAndGet(); + } + + }); + + + try { + underTest.commit(); + fail("exepcted rollback exception"); + } catch (TransactionRolledBackException expected) { + } + + assertEquals("beforeEnd A called once", 1, beforeEndCountA.get()); + assertEquals("beforeEnd B called once", 1, beforeEndCountA.get()); + assertEquals("rollbackCount B 0", 1, rollbackCountB.get()); + assertEquals("rollbackCount A B", rollbackCountA.get(), rollbackCountB.get()); + } + + @Test + public void testSyncIndexCleared() throws Exception { + final AtomicInteger beforeEndCountA = new AtomicInteger(0); + final AtomicInteger rollbackCountA = new AtomicInteger(0); + Synchronization sync = new Synchronization() { + @Override + public void beforeEnd() throws Exception { + beforeEndCountA.getAndIncrement(); + } + @Override + public void afterCommit() throws Exception { + fail("exepcted rollback exception"); + } + @Override + public void afterRollback() throws Exception { + rollbackCountA.incrementAndGet(); + } + }; + + underTest.begin(); + underTest.addSynchronization(sync); + underTest.rollback(); + + assertEquals("beforeEnd", 1, beforeEndCountA.get()); + assertEquals("rollback", 1, rollbackCountA.get()); + + // do it again + underTest.begin(); + underTest.addSynchronization(sync); + underTest.rollback(); + + assertEquals("beforeEnd", 2, beforeEndCountA.get()); + assertEquals("rollback", 2, rollbackCountA.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ZeroPrefetchConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ZeroPrefetchConsumerTest.java new file mode 100644 index 0000000000..d4cecaba06 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/ZeroPrefetchConsumerTest.java @@ -0,0 +1,404 @@ +/** + * 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; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Subscription; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConsumerControl; +import org.apache.activemq.command.ExceptionResponse; +import org.apache.activemq.spring.SpringConsumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ZeroPrefetchConsumerTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(ZeroPrefetchConsumerTest.class); + + protected Connection connection; + protected Queue queue; + protected Queue brokerZeroQueue = new ActiveMQQueue("brokerZeroConfig"); + + public void testCannotUseMessageListener() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + + MessageListener listener = new SpringConsumer(); + try { + consumer.setMessageListener(listener); + fail("Should have thrown JMSException as we cannot use MessageListener with zero prefetch"); + } catch (JMSException e) { + LOG.info("Received expected exception : " + e); + } + } + + public void testPullConsumerWorks() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Hello World!")); + + // now lets receive it + MessageConsumer consumer = session.createConsumer(queue); + Message answer = consumer.receive(5000); + assertNotNull("Should have received a message!", answer); + // check if method will return at all and will return a null + answer = consumer.receive(1); + assertNull("Should have not received a message!", answer); + answer = consumer.receiveNoWait(); + assertNull("Should have not received a message!", answer); + } + + public void testIdleConsumer() throws Exception { + doTestIdleConsumer(false); + } + + public void testIdleConsumerTranscated() throws Exception { + doTestIdleConsumer(true); + } + + private void doTestIdleConsumer(boolean transacted) throws Exception { + Session session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Msg1")); + producer.send(session.createTextMessage("Msg2")); + if (transacted) { + session.commit(); + } + // now lets receive it + MessageConsumer consumer = session.createConsumer(queue); + + session.createConsumer(queue); + TextMessage answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg1"); + if (transacted) { + session.commit(); + } + // this call would return null if prefetchSize > 0 + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg2"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receiveNoWait(); + assertNull("Should have not received a message!", answer); + } + + public void testRecvRecvCommit() throws Exception { + doTestRecvRecvCommit(false); + } + + public void testRecvRecvCommitTranscated() throws Exception { + doTestRecvRecvCommit(true); + } + + private void doTestRecvRecvCommit(boolean transacted) throws Exception { + Session session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Msg1")); + producer.send(session.createTextMessage("Msg2")); + if (transacted) { + session.commit(); + } + // now lets receive it + MessageConsumer consumer = session.createConsumer(queue); + TextMessage answer = (TextMessage)consumer.receiveNoWait(); + assertEquals("Should have received a message!", answer.getText(), "Msg1"); + answer = (TextMessage)consumer.receiveNoWait(); + assertEquals("Should have received a message!", answer.getText(), "Msg2"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receiveNoWait(); + assertNull("Should have not received a message!", answer); + } + + public void testTwoConsumers() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Msg1")); + producer.send(session.createTextMessage("Msg2")); + + // now lets receive it + MessageConsumer consumer1 = session.createConsumer(queue); + MessageConsumer consumer2 = session.createConsumer(queue); + TextMessage answer = (TextMessage)consumer1.receiveNoWait(); + assertEquals("Should have received a message!", answer.getText(), "Msg1"); + answer = (TextMessage)consumer2.receiveNoWait(); + assertEquals("Should have received a message!", answer.getText(), "Msg2"); + + answer = (TextMessage)consumer2.receiveNoWait(); + assertNull("Should have not received a message!", answer); + } + + // https://issues.apache.org/activemq/browse/AMQ-2567 + public void testManyMessageConsumer() throws Exception { + doTestManyMessageConsumer(true); + } + + public void testManyMessageConsumerNoTransaction() throws Exception { + doTestManyMessageConsumer(false); + } + + private void doTestManyMessageConsumer(boolean transacted) throws Exception { + Session session = connection.createSession(transacted, transacted ? Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Msg1")); + producer.send(session.createTextMessage("Msg2")); + producer.send(session.createTextMessage("Msg3")); + producer.send(session.createTextMessage("Msg4")); + producer.send(session.createTextMessage("Msg5")); + producer.send(session.createTextMessage("Msg6")); + producer.send(session.createTextMessage("Msg7")); + producer.send(session.createTextMessage("Msg8")); + if (transacted) { + session.commit(); + } + // now lets receive it + MessageConsumer consumer = session.createConsumer(queue); + + MessageConsumer consumer2 = session.createConsumer(queue); + TextMessage answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg1"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg2"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg3"); + if (transacted) { + session.commit(); + } + // this call would return null if prefetchSize > 0 + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg4"); + if (transacted) { + session.commit(); + } + // Now using other consumer + // this call should return the next message (Msg5) still left on the queue + answer = (TextMessage)consumer2.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg5"); + if (transacted) { + session.commit(); + } + // Now using other consumer + // this call should return the next message still left on the queue + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg6"); + // read one more message without commit + // this call should return the next message still left on the queue + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg7"); + if (transacted) { + session.commit(); + } + // Now using other consumer + // this call should return the next message (Msg5) still left on the queue + answer = (TextMessage)consumer2.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg8"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receiveNoWait(); + assertNull("Should have not received a message!", answer); + } + + public void testManyMessageConsumerWithSend() throws Exception { + doTestManyMessageConsumerWithSend(true); + } + + public void testManyMessageConsumerWithTxSendPrioritySupport() throws Exception { + ((ActiveMQConnection)connection).setMessagePrioritySupported(true); + doTestManyMessageConsumerWithSend(true); + } + + public void testManyMessageConsumerWithSendNoTransaction() throws Exception { + doTestManyMessageConsumerWithSend(false); + } + + private void doTestManyMessageConsumerWithSend(boolean transacted) throws Exception { + Session session = connection.createSession(transacted, transacted ? Session.SESSION_TRANSACTED :Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("Msg1")); + producer.send(session.createTextMessage("Msg2")); + producer.send(session.createTextMessage("Msg3")); + producer.send(session.createTextMessage("Msg4")); + producer.send(session.createTextMessage("Msg5")); + producer.send(session.createTextMessage("Msg6")); + producer.send(session.createTextMessage("Msg7")); + producer.send(session.createTextMessage("Msg8")); + if (transacted) { + session.commit(); + } + // now lets receive it + MessageConsumer consumer = session.createConsumer(queue); + + MessageConsumer consumer2 = session.createConsumer(queue); + TextMessage answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg1"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg2"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg3"); + if (transacted) { + session.commit(); + } + // Now using other consumer take 2 + answer = (TextMessage)consumer2.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg4"); + answer = (TextMessage)consumer2.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg5"); + + // ensure prefetch extension ok by sending another that could get dispatched + producer.send(session.createTextMessage("Msg9")); + if (transacted) { + session.commit(); + } + + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg6"); + // read one more message without commit + // and using other consumer + answer = (TextMessage)consumer2.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg7"); + if (transacted) { + session.commit(); + } + + answer = (TextMessage)consumer2.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg8"); + if (transacted) { + session.commit(); + } + + answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg9"); + if (transacted) { + session.commit(); + } + answer = (TextMessage)consumer.receiveNoWait(); + assertNull("Should have not received a message!", answer); + } + + // https://issues.apache.org/jira/browse/AMQ-4224 + public void testBrokerZeroPrefetchConfig() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(brokerZeroQueue); + producer.send(session.createTextMessage("Msg1")); + // now lets receive it + MessageConsumer consumer = session.createConsumer(brokerZeroQueue); + + TextMessage answer = (TextMessage)consumer.receive(5000); + assertEquals("Should have received a message!", answer.getText(), "Msg1"); + } + + // 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); + + ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer) session.createConsumer(brokerZeroQueue); + assertEquals("broker config prefetch in effect", 0, consumer.info.getCurrentPrefetchSize()); + + // verify sub view broker + Subscription sub = + broker.getRegionBroker().getDestinationMap().get(ActiveMQDestination.transform(brokerZeroQueue)).getConsumers().get(0); + assertEquals("broker sub prefetch is correct", 0, sub.getConsumerInfo().getCurrentPrefetchSize()); + + // manipulate Prefetch (like failover and stomp) + ConsumerControl consumerControl = new ConsumerControl(); + consumerControl.setConsumerId(consumer.info.getConsumerId()); + consumerControl.setDestination(ActiveMQDestination.transform(brokerZeroQueue)); + consumerControl.setPrefetch(1000); // default for a q + + Object reply = ((ActiveMQConnection) connection).getTransport().request(consumerControl); + assertTrue("good request", !(reply instanceof ExceptionResponse)); + assertEquals("broker config prefetch in effect", 0, consumer.info.getCurrentPrefetchSize()); + assertEquals("broker sub prefetch is correct", 0, sub.getConsumerInfo().getCurrentPrefetchSize()); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService brokerService = super.createBroker(); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry zeroPrefetchPolicy = new PolicyEntry(); + zeroPrefetchPolicy.setQueuePrefetch(0); + policyMap.put(ActiveMQDestination.transform(brokerZeroQueue), zeroPrefetchPolicy); + brokerService.setDestinationPolicy(policyMap); + return brokerService; + } + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + super.setUp(); + + connection = createConnection(); + connection.start(); + queue = createQueue(); + } + + @Override + protected void startBroker() throws Exception { + super.startBroker(); + bindAddress = broker.getTransportConnectors().get(0).getConnectUri().toString(); + } + + @Override + protected void tearDown() throws Exception { + connection.close(); + super.tearDown(); + } + + protected Queue createQueue() { + return new ActiveMQQueue(getDestinationString() + "?consumer.prefetchSize=0"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/AdvisoryTempDestinationTests.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/AdvisoryTempDestinationTests.java new file mode 100644 index 0000000000..5e20f79c3b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/AdvisoryTempDestinationTests.java @@ -0,0 +1,232 @@ +/** + * 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.advisory; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.Topic; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.ConstantPendingMessageLimitStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; + +public class AdvisoryTempDestinationTests extends TestCase { + + protected static final int MESSAGE_COUNT = 2000; + protected BrokerService broker; + protected Connection connection; + protected String bindAddress = ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL; + protected int topicCount; + + + public void testNoSlowConsumerAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue queue = s.createTemporaryQueue(); + MessageConsumer consumer = s.createConsumer(queue); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + } + }); + Topic advisoryTopic = AdvisorySupport + .getSlowConsumerAdvisoryTopic((ActiveMQDestination) queue); + s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + // start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + } + Message msg = advisoryConsumer.receive(1000); + assertNull(msg); + } + + public void testSlowConsumerAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue queue = s.createTemporaryQueue(); + MessageConsumer consumer = s.createConsumer(queue); + assertNotNull(consumer); + + Topic advisoryTopic = AdvisorySupport + .getSlowConsumerAdvisoryTopic((ActiveMQDestination) queue); + s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + // start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + } + Message msg = advisoryConsumer.receive(1000); + assertNotNull(msg); + } + + public void testMessageDeliveryAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue queue = s.createTemporaryQueue(); + MessageConsumer consumer = s.createConsumer(queue); + assertNotNull(consumer); + + Topic advisoryTopic = AdvisorySupport.getMessageDeliveredAdvisoryTopic((ActiveMQDestination) queue); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + //start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + + Message msg = advisoryConsumer.receive(1000); + assertNotNull(msg); + } + + public void testTempMessageConsumedAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue queue = s.createTemporaryQueue(); + MessageConsumer consumer = s.createConsumer(queue); + + Topic advisoryTopic = AdvisorySupport.getMessageConsumedAdvisoryTopic((ActiveMQDestination) queue); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + //start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + String id = m.getJMSMessageID(); + Message msg = consumer.receive(1000); + assertNotNull(msg); + + msg = advisoryConsumer.receive(1000); + assertNotNull(msg); + + ActiveMQMessage message = (ActiveMQMessage) msg; + ActiveMQMessage payload = (ActiveMQMessage) message.getDataStructure(); + String originalId = payload.getJMSMessageID(); + assertEquals(originalId, id); + } + + public void testMessageExpiredAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + assertNotNull(consumer); + + Topic advisoryTopic = AdvisorySupport.getExpiredMessageTopic((ActiveMQDestination) queue); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + //start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + producer.setTimeToLive(1); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + } + + Message msg = advisoryConsumer.receive(5000); + assertNotNull(msg); + } + + @Override + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + ConnectionFactory factory = createConnectionFactory(); + connection = factory.createConnection(); + connection.start(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + connection.close(); + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() + throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory( + ActiveMQConnection.DEFAULT_BROKER_URL); + return cf; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.setPersistent(false); + ConstantPendingMessageLimitStrategy strategy = new ConstantPendingMessageLimitStrategy(); + strategy.setLimit(10); + PolicyEntry tempQueueEntry = createPolicyEntry(strategy); + tempQueueEntry.setTempQueue(true); + PolicyEntry tempTopicEntry = createPolicyEntry(strategy); + tempTopicEntry.setTempTopic(true); + + PolicyMap pMap = new PolicyMap(); + final List policyEntries = new ArrayList(); + policyEntries.add(tempQueueEntry); + policyEntries.add(tempTopicEntry); + pMap.setPolicyEntries(policyEntries); + + answer.setDestinationPolicy(pMap); + answer.addConnector(bindAddress); + answer.setDeleteAllMessagesOnStartup(true); + } + + private PolicyEntry createPolicyEntry(ConstantPendingMessageLimitStrategy strategy) { + PolicyEntry policy = new PolicyEntry(); + policy.setAdvisoryForFastProducers(true); + policy.setAdvisoryForConsumed(true); + policy.setAdvisoryForDelivery(true); + policy.setAdvisoryForDiscardingMessages(true); + policy.setAdvisoryForSlowConsumers(true); + policy.setAdvisoryWhenFull(true); + policy.setProducerFlowControl(false); + policy.setPendingMessageLimitStrategy(strategy); + + return policy; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/AdvisoryTests.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/AdvisoryTests.java new file mode 100644 index 0000000000..4bb90532f5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/AdvisoryTests.java @@ -0,0 +1,238 @@ +/** + * 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.advisory; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.Topic; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.ConstantPendingMessageLimitStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; + +/** + * + */ +public class AdvisoryTests extends TestCase { + protected static final int MESSAGE_COUNT = 2000; + protected BrokerService broker; + protected Connection connection; + protected String bindAddress = ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL; + protected int topicCount; + + + public void testNoSlowConsumerAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + } + }); + Topic advisoryTopic = AdvisorySupport + .getSlowConsumerAdvisoryTopic((ActiveMQDestination) queue); + s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + // start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + } + Message msg = advisoryConsumer.receive(1000); + assertNull(msg); + } + + public void testSlowConsumerAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + assertNotNull(consumer); + + Topic advisoryTopic = AdvisorySupport + .getSlowConsumerAdvisoryTopic((ActiveMQDestination) queue); + s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + // start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + } + Message msg = advisoryConsumer.receive(1000); + assertNotNull(msg); + } + + public void testMessageDeliveryAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + assertNotNull(consumer); + + Topic advisoryTopic = AdvisorySupport.getMessageDeliveredAdvisoryTopic((ActiveMQDestination) queue); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + //start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + + Message msg = advisoryConsumer.receive(1000); + assertNotNull(msg); + } + + public void testMessageConsumedAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + + Topic advisoryTopic = AdvisorySupport.getMessageConsumedAdvisoryTopic((ActiveMQDestination) queue); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + //start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + String id = m.getJMSMessageID(); + Message msg = consumer.receive(1000); + assertNotNull(msg); + + msg = advisoryConsumer.receive(1000); + assertNotNull(msg); + + ActiveMQMessage message = (ActiveMQMessage) msg; + ActiveMQMessage payload = (ActiveMQMessage) message.getDataStructure(); + String originalId = payload.getJMSMessageID(); + assertEquals(originalId, id); + } + + public void testMessageExpiredAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + assertNotNull(consumer); + + Topic advisoryTopic = AdvisorySupport.getExpiredMessageTopic((ActiveMQDestination) queue); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + //start throwing messages at the consumer + MessageProducer producer = s.createProducer(queue); + producer.setTimeToLive(1); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = s.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + } + + Message msg = advisoryConsumer.receive(2000); + assertNotNull(msg); + } + + public void xtestMessageDiscardedAdvisory() throws Exception { + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = s.createTopic(getClass().getName()); + MessageConsumer consumer = s.createConsumer(topic); + assertNotNull(consumer); + + Topic advisoryTopic = AdvisorySupport.getMessageDiscardedAdvisoryTopic((ActiveMQDestination) topic); + MessageConsumer advisoryConsumer = s.createConsumer(advisoryTopic); + //start throwing messages at the consumer + MessageProducer producer = s.createProducer(topic); + int count = (new ActiveMQPrefetchPolicy().getTopicPrefetch() * 2); + for (int i = 0; i < count; i++) { + BytesMessage m = s.createBytesMessage(); + producer.send(m); + } + + Message msg = advisoryConsumer.receive(1000); + assertNotNull(msg); + } + + @Override + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + ConnectionFactory factory = createConnectionFactory(); + connection = factory.createConnection(); + connection.start(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + connection.close(); + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() + throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory( + ActiveMQConnection.DEFAULT_BROKER_URL); + return cf; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.setPersistent(false); + PolicyEntry policy = new PolicyEntry(); + policy.setAdvisoryForFastProducers(true); + policy.setAdvisoryForConsumed(true); + policy.setAdvisoryForDelivery(true); + policy.setAdvisoryForDiscardingMessages(true); + policy.setAdvisoryForSlowConsumers(true); + policy.setAdvisoryWhenFull(true); + policy.setProducerFlowControl(false); + ConstantPendingMessageLimitStrategy strategy = new ConstantPendingMessageLimitStrategy(); + strategy.setLimit(10); + policy.setPendingMessageLimitStrategy(strategy); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + answer.setDestinationPolicy(pMap); + answer.addConnector(bindAddress); + answer.setDeleteAllMessagesOnStartup(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/ConsumerListenerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/ConsumerListenerTest.java new file mode 100644 index 0000000000..2c5f9cd15e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/ConsumerListenerTest.java @@ -0,0 +1,152 @@ +/** + * 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.advisory; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class ConsumerListenerTest extends EmbeddedBrokerTestSupport implements ConsumerListener { + private static final Logger LOG = LoggerFactory.getLogger(ConsumerListenerTest.class); + + protected Session consumerSession1; + protected Session consumerSession2; + protected int consumerCounter; + protected ConsumerEventSource consumerEventSource; + protected BlockingQueue eventQueue = new ArrayBlockingQueue(1000); + private Connection connection; + + public void testConsumerEvents() throws Exception { + consumerEventSource.start(); + + consumerSession1 = createConsumer(); + assertConsumerEvent(1, true); + + consumerSession2 = createConsumer(); + assertConsumerEvent(2, true); + + consumerSession1.close(); + consumerSession1 = null; + assertConsumerEvent(1, false); + + consumerSession2.close(); + consumerSession2 = null; + assertConsumerEvent(0, false); + } + + public void testListenWhileAlreadyConsumersActive() throws Exception { + consumerSession1 = createConsumer(); + consumerSession2 = createConsumer(); + + consumerEventSource.start(); + assertConsumerEvent(2, true); + assertConsumerEvent(2, true); + + consumerSession1.close(); + consumerSession1 = null; + assertConsumerEvent(1, false); + + consumerSession2.close(); + consumerSession2 = null; + assertConsumerEvent(0, false); + } + + public void testConsumerEventsOnTemporaryDestination() throws Exception { + + Session s = connection.createSession(true,Session.AUTO_ACKNOWLEDGE); + Destination dest = useTopic ? s.createTemporaryTopic() : s.createTemporaryQueue(); + consumerEventSource = new ConsumerEventSource(connection, dest); + consumerEventSource.setConsumerListener(this); + consumerEventSource.start(); + MessageConsumer consumer = s.createConsumer(dest); + assertConsumerEvent(1,true); + consumer.close(); + assertConsumerEvent(0,false); + } + + public void onConsumerEvent(ConsumerEvent event) { + eventQueue.add(event); + } + + protected void setUp() throws Exception { + super.setUp(); + + connection = createConnection(); + connection.start(); + consumerEventSource = new ConsumerEventSource(connection, destination); + consumerEventSource.setConsumerListener(this); + } + + protected void tearDown() throws Exception { + if (consumerEventSource != null) { + consumerEventSource.stop(); + } + if (consumerSession2 != null) { + consumerSession2.close(); + } + if (consumerSession1 != null) { + consumerSession1.close(); + } + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + protected void assertConsumerEvent(int count, boolean started) throws InterruptedException { + ConsumerEvent event = waitForConsumerEvent(); + assertEquals("Consumer count", count, event.getConsumerCount()); + assertEquals("started", started, event.isStarted()); + } + + protected Session createConsumer() throws JMSException { + final String consumerText = "Consumer: " + (++consumerCounter); + LOG.info("Creating consumer: " + consumerText + " on destination: " + destination); + + Session answer = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = answer.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + LOG.info("Received message by: " + consumerText + " message: " + message); + } + }); + return answer; + } + + protected ConsumerEvent waitForConsumerEvent() throws InterruptedException { + ConsumerEvent answer = eventQueue.poll(100000, TimeUnit.MILLISECONDS); + assertTrue("Should have received a consumer event!", answer != null); + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/DestinationListenerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/DestinationListenerTest.java new file mode 100644 index 0000000000..01dc443123 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/DestinationListenerTest.java @@ -0,0 +1,129 @@ +/** + * 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.advisory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.jms.Session; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.EmbeddedBrokerTestSupport; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +/** + * + */ +public class DestinationListenerTest extends EmbeddedBrokerTestSupport implements DestinationListener { + private static final transient Logger LOG = LoggerFactory.getLogger(DestinationListenerTest.class); + protected ActiveMQConnection connection; + protected ActiveMQQueue sampleQueue = new ActiveMQQueue("foo.bar"); + protected ActiveMQTopic sampleTopic = new ActiveMQTopic("cheese"); + protected List newDestinations = new ArrayList(); + + public void testDestiationSourceHasInitialDestinations() throws Exception { + Thread.sleep(1000); + + DestinationSource destinationSource = connection.getDestinationSource(); + Set queues = destinationSource.getQueues(); + Set topics = destinationSource.getTopics(); + + LOG.info("Queues: " + queues); + LOG.info("Topics: " + topics); + + assertTrue("The queues should not be empty!", !queues.isEmpty()); + assertTrue("The topics should not be empty!", !topics.isEmpty()); + + assertTrue("queues contains initial queue: " + queues, queues.contains(sampleQueue)); + assertTrue("topics contains initial topic: " + queues, topics.contains(sampleTopic)); + } + + public void testConsumerForcesNotificationOfNewDestination() throws Exception { + // now lets cause a destination to be created + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue newQueue = new ActiveMQQueue("Test.Cheese"); + session.createConsumer(newQueue); + + Thread.sleep(3000); + + assertThat(newQueue, isIn(newDestinations)); + + LOG.info("New destinations are: " + newDestinations); + } + + public void testProducerForcesNotificationOfNewDestination() throws Exception { + // now lets cause a destination to be created + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQQueue newQueue = new ActiveMQQueue("Test.Beer"); + MessageProducer producer = session.createProducer(newQueue); + TextMessage message = session.createTextMessage("world"); + producer.send(message); + + Thread.sleep(3000); + + assertThat(newQueue, isIn(newDestinations)); + + LOG.info("New destinations are: " + newDestinations); + } + + public void onDestinationEvent(DestinationEvent event) { + ActiveMQDestination destination = event.getDestination(); + if (event.isAddOperation()) { + LOG.info("Added: " + destination); + newDestinations.add(destination); + } + else { + LOG.info("Removed: " + destination); + newDestinations.remove(destination); + } + } + + protected void setUp() throws Exception { + super.setUp(); + + connection = (ActiveMQConnection) createConnection(); + connection.start(); + connection.getDestinationSource().setDestinationListener(this); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.setDestinations(new ActiveMQDestination[]{ + sampleQueue, + sampleTopic + }); + return broker; + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/ProducerListenerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/ProducerListenerTest.java new file mode 100644 index 0000000000..dfa1b5e39b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/ProducerListenerTest.java @@ -0,0 +1,151 @@ +/** + * 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.advisory; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class ProducerListenerTest extends EmbeddedBrokerTestSupport implements ProducerListener { + private static final Logger LOG = LoggerFactory.getLogger(ProducerListenerTest.class); + + protected Session consumerSession1; + protected Session consumerSession2; + protected int consumerCounter; + protected ProducerEventSource producerEventSource; + protected BlockingQueue eventQueue = new ArrayBlockingQueue(1000); + private Connection connection; + + public void testProducerEvents() throws Exception { + producerEventSource.start(); + + consumerSession1 = createProducer(); + assertProducerEvent(1, true); + + consumerSession2 = createProducer(); + assertProducerEvent(2, true); + + consumerSession1.close(); + consumerSession1 = null; + assertProducerEvent(1, false); + + consumerSession2.close(); + consumerSession2 = null; + assertProducerEvent(0, false); + } + + public void testListenWhileAlreadyConsumersActive() throws Exception { + consumerSession1 = createProducer(); + consumerSession2 = createProducer(); + + producerEventSource.start(); + assertProducerEvent(2, true); + assertProducerEvent(2, true); + + consumerSession1.close(); + consumerSession1 = null; + assertProducerEvent(1, false); + + consumerSession2.close(); + consumerSession2 = null; + assertProducerEvent(0, false); + } + + public void testConsumerEventsOnTemporaryDestination() throws Exception { + + Session s = connection.createSession(true,Session.AUTO_ACKNOWLEDGE); + Destination dest = useTopic ? s.createTemporaryTopic() : s.createTemporaryQueue(); + producerEventSource = new ProducerEventSource(connection, dest); + producerEventSource.setProducerListener(this); + producerEventSource.start(); + MessageProducer producer = s.createProducer(dest); + assertProducerEvent(1, true); + producer.close(); + assertProducerEvent(0, false); + } + + + + @Override + public void onProducerEvent(ProducerEvent event) { + eventQueue.add(event); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + connection = createConnection(); + connection.start(); + producerEventSource = new ProducerEventSource(connection, destination); + producerEventSource.setProducerListener(this); + } + + @Override + protected void tearDown() throws Exception { + if (producerEventSource != null) { + producerEventSource.stop(); + } + if (consumerSession2 != null) { + consumerSession2.close(); + } + if (consumerSession1 != null) { + consumerSession1.close(); + } + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + protected void assertProducerEvent(int count, boolean started) throws InterruptedException { + ProducerEvent event = waitForProducerEvent(); + assertEquals("Producer count", count, event.getProducerCount()); + assertEquals("started", started, event.isStarted()); + } + + protected Session createProducer() throws JMSException { + final String consumerText = "Consumer: " + (++consumerCounter); + LOG.info("Creating consumer: " + consumerText + " on destination: " + destination); + + Session answer = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = answer.createProducer(destination); + assertNotNull(producer); + + return answer; + } + + protected ProducerEvent waitForProducerEvent() throws InterruptedException { + ProducerEvent answer = eventQueue.poll(100000, TimeUnit.MILLISECONDS); + assertTrue("Should have received a consumer event!", answer != null); + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempDestDeleteTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempDestDeleteTest.java new file mode 100644 index 0000000000..123c7787dd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempDestDeleteTest.java @@ -0,0 +1,149 @@ +/** + * 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.advisory; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.command.ActiveMQTempQueue; +import org.apache.activemq.command.ActiveMQTempTopic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TempDestDeleteTest extends EmbeddedBrokerTestSupport implements ConsumerListener { + private static final Logger LOG = LoggerFactory.getLogger(TempDestDeleteTest.class); + + protected int consumerCounter; + protected ConsumerEventSource topicConsumerEventSource; + protected BlockingQueue eventQueue = new ArrayBlockingQueue(1000); + + private ConsumerEventSource queueConsumerEventSource; + private Connection connection; + private Session session; + private ActiveMQTempTopic tempTopic; + private ActiveMQTempQueue tempQueue; + + public void testDeleteTempTopicDeletesAvisoryTopics() throws Exception { + topicConsumerEventSource.start(); + + MessageConsumer consumer = createConsumer(tempTopic); + assertConsumerEvent(1, true); + + Topic advisoryTopic = AdvisorySupport.getConsumerAdvisoryTopic(tempTopic); + assertTrue(destinationExists(advisoryTopic)); + + consumer.close(); + + // Once we delete the topic, the advisory topic for the destination + // should also be deleted. + tempTopic.delete(); + + assertFalse(destinationExists(advisoryTopic)); + } + + public void testDeleteTempQueueDeletesAvisoryTopics() throws Exception { + queueConsumerEventSource.start(); + + MessageConsumer consumer = createConsumer(tempQueue); + assertConsumerEvent(1, true); + + Topic advisoryTopic = AdvisorySupport.getConsumerAdvisoryTopic(tempQueue); + assertTrue(destinationExists(advisoryTopic)); + + consumer.close(); + + // Once we delete the queue, the advisory topic for the destination + // should also be deleted. + tempQueue.delete(); + + assertFalse(destinationExists(advisoryTopic)); + } + + private boolean destinationExists(Destination dest) throws Exception { + RegionBroker rb = (RegionBroker)broker.getBroker().getAdaptor(RegionBroker.class); + return rb.getTopicRegion().getDestinationMap().containsKey(dest) || rb.getQueueRegion().getDestinationMap().containsKey(dest) + || rb.getTempTopicRegion().getDestinationMap().containsKey(dest) || rb.getTempQueueRegion().getDestinationMap().containsKey(dest); + } + + public void onConsumerEvent(ConsumerEvent event) { + eventQueue.add(event); + } + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + connection.start(); + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + tempTopic = (ActiveMQTempTopic)session.createTemporaryTopic(); + topicConsumerEventSource = new ConsumerEventSource(connection, tempTopic); + topicConsumerEventSource.setConsumerListener(this); + + tempQueue = (ActiveMQTempQueue)session.createTemporaryQueue(); + queueConsumerEventSource = new ConsumerEventSource(connection, tempQueue); + queueConsumerEventSource.setConsumerListener(this); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + protected void assertConsumerEvent(int count, boolean started) throws InterruptedException { + ConsumerEvent event = waitForConsumerEvent(); + assertEquals("Consumer count", count, event.getConsumerCount()); + assertEquals("started", started, event.isStarted()); + } + + protected MessageConsumer createConsumer(Destination dest) throws JMSException { + final String consumerText = "Consumer: " + (++consumerCounter); + LOG.info("Creating consumer: " + consumerText + " on destination: " + dest); + + MessageConsumer consumer = session.createConsumer(dest); + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + LOG.info("Received message by: " + consumerText + " message: " + message); + } + }); + return consumer; + } + + protected ConsumerEvent waitForConsumerEvent() throws InterruptedException { + ConsumerEvent answer = eventQueue.poll(1000, TimeUnit.MILLISECONDS); + assertTrue("Should have received a consumer event!", answer != null); + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempDestLoadTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempDestLoadTest.java new file mode 100644 index 0000000000..cab4e5924b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempDestLoadTest.java @@ -0,0 +1,115 @@ +/** + * 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.advisory; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.TemporaryTopic; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.RegionBroker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TempDestLoadTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(TempDestLoadTest.class); + + protected int consumerCounter; + private Connection connection; + private Session session; + private static final int MESSAGE_COUNT = 2000; + + public void testLoadTempAdvisoryQueues() throws Exception { + + for (int i = 0; i < MESSAGE_COUNT; i++) { + TemporaryQueue tempQueue = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(tempQueue); + MessageProducer producer = session.createProducer(tempQueue); + consumer.close(); + producer.close(); + tempQueue.delete(); + } + + AdvisoryBroker ab = (AdvisoryBroker) broker.getBroker().getAdaptor( + AdvisoryBroker.class); + + assertTrue(ab.getAdvisoryDestinations().size() == 0); + assertTrue(ab.getAdvisoryConsumers().size() == 0); + assertTrue(ab.getAdvisoryProducers().size() == 0); + + RegionBroker rb = (RegionBroker) broker.getBroker().getAdaptor(RegionBroker.class); + + for (Destination dest : rb.getDestinationMap().values()) { + LOG.debug("Destination: {}", dest); + } + + // there should be at least 2 destinations - advisories - + // 1 for the connection + 1 generic ones + assertTrue("Should be at least 2 destinations", rb.getDestinationMap().size() > 2); + } + + public void testLoadTempAdvisoryTopics() throws Exception { + for (int i = 0; i < MESSAGE_COUNT; i++) { + TemporaryTopic tempTopic = session.createTemporaryTopic(); + MessageConsumer consumer = session.createConsumer(tempTopic); + MessageProducer producer = session.createProducer(tempTopic); + consumer.close(); + producer.close(); + tempTopic.delete(); + } + + AdvisoryBroker ab = (AdvisoryBroker) broker.getBroker().getAdaptor( + AdvisoryBroker.class); + assertTrue(ab.getAdvisoryDestinations().size() == 0); + assertTrue(ab.getAdvisoryConsumers().size() == 0); + assertTrue(ab.getAdvisoryProducers().size() == 0); + RegionBroker rb = (RegionBroker) broker.getBroker().getAdaptor( + RegionBroker.class); + + for (Destination dest : rb.getDestinationMap().values()) { + LOG.debug("Destination: {}", dest); + } + + // there should be at least 2 destinations - advisories - + // 1 for the connection + 1 generic ones + assertTrue("Should be at least 2 destinations", rb.getDestinationMap().size() > 2); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempQueueMemoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempQueueMemoryTest.java new file mode 100644 index 0000000000..9bf8ed1426 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/advisory/TempQueueMemoryTest.java @@ -0,0 +1,171 @@ +/** + * 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.advisory; + +import java.util.Vector; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; + +public class TempQueueMemoryTest extends EmbeddedBrokerTestSupport { + + protected Connection serverConnection; + protected Session serverSession; + protected Connection clientConnection; + protected Session clientSession; + protected Destination serverDestination; + protected int messagesToSend = 10; + protected boolean deleteTempQueue = true; + protected boolean serverTransactional = false; + protected boolean clientTransactional = false; + protected int numConsumers = 1; + protected int numProducers = 1; + + public void testConcurrentProducerRequestReply() throws Exception { + numProducers = 10; + testLoadRequestReply(); + } + + public void testLoadRequestReply() throws Exception { + for (int i = 0; i < numConsumers; i++) { + serverSession.createConsumer(serverDestination).setMessageListener(new MessageListener() { + @Override + public void onMessage(Message msg) { + try { + Destination replyTo = msg.getJMSReplyTo(); + MessageProducer producer = serverSession.createProducer(replyTo); + producer.send(replyTo, msg); + if (serverTransactional) { + serverSession.commit(); + } + producer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + class Producer extends Thread { + private final int numToSend; + + public Producer(int numToSend) { + this.numToSend = numToSend; + } + + @Override + public void run() { + try { + Session session = clientConnection.createSession(clientTransactional, clientTransactional ? + Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(serverDestination); + + for (int i = 0; i < numToSend; i++) { + TemporaryQueue replyTo = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(replyTo); + Message msg = session.createMessage(); + msg.setJMSReplyTo(replyTo); + producer.send(msg); + if (clientTransactional) { + session.commit(); + } + consumer.receive(); + if (clientTransactional) { + session.commit(); + } + consumer.close(); + if (deleteTempQueue) { + replyTo.delete(); + } else { + // temp queue will be cleaned up on clientConnection.close + } + } + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + Vector threads = new Vector(numProducers); + for (int i = 0; i < numProducers; i++) { + threads.add(new Producer(messagesToSend / numProducers)); + } + startAndJoinThreads(threads); + + clientSession.close(); + serverSession.close(); + clientConnection.close(); + serverConnection.close(); + + AdvisoryBroker ab = (AdvisoryBroker) broker.getBroker().getAdaptor(AdvisoryBroker.class); + + // The server destination will be left + assertTrue(ab.getAdvisoryDestinations().size() == 1); + + assertTrue("should be zero but is " + ab.getAdvisoryConsumers().size(), ab.getAdvisoryConsumers().size() == 0); + assertTrue("should be zero but is " + ab.getAdvisoryProducers().size(), ab.getAdvisoryProducers().size() == 0); + + RegionBroker rb = (RegionBroker) broker.getBroker().getAdaptor(RegionBroker.class); + + assertTrue(rb.getDestinationMap().size() >= 6); + } + + private void startAndJoinThreads(Vector threads) throws Exception { + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + serverConnection = createConnection(); + serverConnection.start(); + serverSession = serverConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + clientConnection = createConnection(); + clientConnection.start(); + clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + serverDestination = createDestination(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + serverTransactional = clientTransactional = false; + numConsumers = numProducers = 1; + messagesToSend = 2000; + } + + @Override + protected ActiveMQDestination createDestination() { + return new ActiveMQQueue(getClass().getName()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/BlobTransferPolicyUriTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/BlobTransferPolicyUriTest.java new file mode 100644 index 0000000000..40405699b2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/BlobTransferPolicyUriTest.java @@ -0,0 +1,32 @@ +/** + * 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.blob; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * + */ +public class BlobTransferPolicyUriTest extends TestCase { + public void testBlobTransferPolicyIsConfiguredViaUri() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?jms.blobTransferPolicy.defaultUploadUrl=http://foo.com"); + BlobTransferPolicy policy = factory.getBlobTransferPolicy(); + assertEquals("http://foo.com", policy.getDefaultUploadUrl()); + assertEquals("http://foo.com", policy.getUploadUrl()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobDownloadStrategyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobDownloadStrategyTest.java new file mode 100644 index 0000000000..0875a5b3c8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobDownloadStrategyTest.java @@ -0,0 +1,108 @@ +/** + * 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.blob; + +import java.io.File; +import java.io.FileWriter; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.jms.JMSException; + +import org.apache.activemq.command.ActiveMQBlobMessage; + +public class FTPBlobDownloadStrategyTest extends FTPTestSupport { + + final int FILE_SIZE = Short.MAX_VALUE * 10; + + public void testDownload() throws Exception { + setConnection(); + + // create file + File uploadFile = new File(ftpHomeDirFile, "test.txt"); + FileWriter wrt = new FileWriter(uploadFile); + + wrt.write("hello world"); + + for(int ix = 0; ix < FILE_SIZE; ++ix ) { + wrt.write("a"); + } + + wrt.close(); + + ActiveMQBlobMessage message = new ActiveMQBlobMessage(); + BlobDownloadStrategy strategy = new FTPBlobDownloadStrategy(new BlobTransferPolicy()); + InputStream stream; + try { + message.setURL(new URL(ftpUrl + "test.txt")); + stream = strategy.getInputStream(message); + int i = stream.read(); + StringBuilder sb = new StringBuilder(2048); + while(i != -1) { + sb.append((char)i); + i = stream.read(); + } + assertEquals("hello world", sb.toString().substring(0, "hello world".length())); + assertEquals(FILE_SIZE, sb.toString().substring("hello world".length()).length()); + + assertTrue(uploadFile.exists()); + strategy.deleteFile(message); + assertFalse(uploadFile.exists()); + + } catch (Exception e) { + e.printStackTrace(); + assertTrue(false); + } + } + + public void testWrongAuthentification() throws MalformedURLException { + ActiveMQBlobMessage message = new ActiveMQBlobMessage(); + BlobDownloadStrategy strategy = new FTPBlobDownloadStrategy(new BlobTransferPolicy()); + try { + message.setURL(new URL("ftp://" + userNamePass + "_wrong:" + userNamePass + "@localhost:" + ftpPort + "/ftptest/")); + strategy.getInputStream(message); + } catch(JMSException e) { + assertEquals("Wrong Exception", "Cant Authentificate to FTP-Server", e.getMessage()); + return; + } catch(Exception e) { + System.out.println(e); + assertTrue("Wrong Exception "+ e, false); + return; + } + + assertTrue("Expect Exception", false); + } + + public void testWrongFTPPort() throws MalformedURLException { + ActiveMQBlobMessage message = new ActiveMQBlobMessage(); + BlobDownloadStrategy strategy = new FTPBlobDownloadStrategy(new BlobTransferPolicy()); + try { + message.setURL(new URL("ftp://" + userNamePass + ":" + userNamePass + "@localhost:" + 422 + "/ftptest/")); + strategy.getInputStream(message); + } catch(JMSException e) { + assertEquals("Wrong Exception", "Problem connecting the FTP-server", e.getMessage()); + return; + } catch(Exception e) { + e.printStackTrace(); + assertTrue("Wrong Exception "+ e, false); + return; + } + + assertTrue("Expect Exception", false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobTest.java new file mode 100644 index 0000000000..4aecc09529 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobTest.java @@ -0,0 +1,75 @@ +/** + * 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.blob; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStream; + +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.BlobMessage; +import org.apache.activemq.command.ActiveMQBlobMessage; + +public class FTPBlobTest extends FTPTestSupport { + + public void testBlobFile() throws Exception { + setConnection(); + // first create Message + File file = File.createTempFile("amq-data-file-", ".dat"); + // lets write some data + String content = "hello world " + System.currentTimeMillis(); + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.append(content); + writer.close(); + + ActiveMQSession session = (ActiveMQSession) connection.createSession( + false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + MessageConsumer consumer = session.createConsumer(destination); + BlobMessage message = session.createBlobMessage(file); + message.setName("fileName"); + + producer.send(message); + Thread.sleep(1000); + + // check message send + Message msg = consumer.receive(1000); + assertTrue(msg instanceof ActiveMQBlobMessage); + + assertEquals("name is correct", "fileName", ((ActiveMQBlobMessage)msg).getName()); + InputStream input = ((ActiveMQBlobMessage) msg).getInputStream(); + StringBuilder b = new StringBuilder(); + int i = input.read(); + while (i != -1) { + b.append((char) i); + i = input.read(); + } + input.close(); + File uploaded = new File(ftpHomeDirFile, msg.getJMSMessageID().toString().replace(":", "_")); + assertEquals(content, b.toString()); + assertTrue(uploaded.exists()); + ((ActiveMQBlobMessage)msg).deleteFile(); + assertFalse(uploaded.exists()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobUploadStrategyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobUploadStrategyTest.java new file mode 100644 index 0000000000..cac9a0aabd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPBlobUploadStrategyTest.java @@ -0,0 +1,75 @@ +/** + * 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.blob; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; + +import javax.jms.JMSException; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.command.ActiveMQBlobMessage; + + +public class FTPBlobUploadStrategyTest extends FTPTestSupport { + + public void testFileUpload() throws Exception { + setConnection(); + File file = File.createTempFile("amq-data-file-", ".dat"); + // lets write some data + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.append("hello world"); + writer.close(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ((ActiveMQConnection)connection).setCopyMessageOnSend(false); + + ActiveMQBlobMessage message = (ActiveMQBlobMessage) ((ActiveMQSession)session).createBlobMessage(file); + message.setJMSMessageID("testmessage"); + message.onSend(); + assertEquals(ftpUrl + "ID_testmessage", message.getURL().toString()); + File uploaded = new File(ftpHomeDirFile, "ID_testmessage"); + assertTrue("File doesn't exists", uploaded.exists()); + } + + public void testWriteDenied() throws Exception { + userNamePass = "guest"; + setConnection(); + File file = File.createTempFile("amq-data-file-", ".dat"); + // lets write some data + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.append("hello world"); + writer.close(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ((ActiveMQConnection)connection).setCopyMessageOnSend(false); + + ActiveMQBlobMessage message = (ActiveMQBlobMessage) ((ActiveMQSession)session).createBlobMessage(file); + message.setJMSMessageID("testmessage"); + try { + message.onSend(); + } catch (JMSException e) { + e.printStackTrace(); + return; + } + fail("Should have failed with permission denied exception!"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPTestSupport.java new file mode 100644 index 0000000000..6145f3be06 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FTPTestSupport.java @@ -0,0 +1,124 @@ +/** + * 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.blob; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Connection; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.util.IOHelper; +import org.apache.ftpserver.FtpServer; +import org.apache.ftpserver.FtpServerFactory; +import org.apache.ftpserver.ftplet.Authority; +import org.apache.ftpserver.ftplet.UserManager; +import org.apache.ftpserver.listener.ListenerFactory; +import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory; +import org.apache.ftpserver.usermanager.impl.BaseUser; +import org.apache.ftpserver.usermanager.impl.WritePermission; +import org.jmock.Mockery; + +public abstract class FTPTestSupport extends EmbeddedBrokerTestSupport { + + protected static final String ftpServerListenerName = "default"; + protected Connection connection; + protected FtpServer server; + String userNamePass = "activemq"; + + Mockery context = null; + String ftpUrl; + int ftpPort; + + final File ftpHomeDirFile = new File("target/FTPBlobTest/ftptest"); + + protected void setUp() throws Exception { + + if (ftpHomeDirFile.getParentFile().exists()) { + IOHelper.deleteFile(ftpHomeDirFile.getParentFile()); + } + ftpHomeDirFile.mkdirs(); + ftpHomeDirFile.getParentFile().deleteOnExit(); + + FtpServerFactory serverFactory = new FtpServerFactory(); + ListenerFactory factory = new ListenerFactory(); + + PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory(); + UserManager userManager = userManagerFactory.createUserManager(); + + BaseUser user = new BaseUser(); + user.setName("activemq"); + user.setPassword("activemq"); + user.setHomeDirectory(ftpHomeDirFile.getParent()); + + // authorize user + List auths = new ArrayList(); + Authority auth = new WritePermission(); + auths.add(auth); + user.setAuthorities(auths); + + userManager.save(user); + + BaseUser guest = new BaseUser(); + guest.setName("guest"); + guest.setPassword("guest"); + guest.setHomeDirectory(ftpHomeDirFile.getParent()); + + userManager.save(guest); + + serverFactory.setUserManager(userManager); + factory.setPort(0); + serverFactory.addListener(ftpServerListenerName, factory + .createListener()); + server = serverFactory.createServer(); + server.start(); + ftpPort = serverFactory.getListener(ftpServerListenerName) + .getPort(); + super.setUp(); + } + + public void setConnection() throws Exception { + ftpUrl = "ftp://" + + userNamePass + + ":" + + userNamePass + + "@localhost:" + + ftpPort + + "/ftptest/"; + bindAddress = "vm://localhost?jms.blobTransferPolicy.defaultUploadUrl=" + ftpUrl; + + connectionFactory = createConnectionFactory(); + + connection = createConnection(); + connection.start(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.stop(); + } + super.tearDown(); + if (server != null) { + server.stop(); + } + IOHelper.deleteFile(ftpHomeDirFile.getParentFile()); + } + + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FilesystemBlobTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FilesystemBlobTest.java new file mode 100644 index 0000000000..1754689c71 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/blob/FilesystemBlobTest.java @@ -0,0 +1,104 @@ +/** + * 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.blob; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStream; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.BlobMessage; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.command.ActiveMQBlobMessage; +import org.apache.activemq.util.IOHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class FilesystemBlobTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(FilesystemBlobTest.class); + + private Connection connection; + private final String tmpDir = System.getProperty("user.dir") + "/target/FilesystemBlobTest"; + @Override + public void setUp() throws Exception { + super.setUp(); + // replace \ with / to let it work on windows too + String fileUrl = "file:///" +tmpDir.replaceAll("\\\\", "/"); + LOG.info("Using file: " + fileUrl); + bindAddress = "vm://localhost?jms.blobTransferPolicy.defaultUploadUrl=" + fileUrl; + + connectionFactory = createConnectionFactory(); + + connection = createConnection(); + connection.start(); + } + + public void testBlobFile() throws Exception { + // first create Message + File file = File.createTempFile("amq-data-file-", ".dat"); + // lets write some data + String content = "hello world " + System.currentTimeMillis(); + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.append(content); + writer.close(); + + ActiveMQSession session = (ActiveMQSession) connection.createSession( + false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + MessageConsumer consumer = session.createConsumer(destination); + BlobMessage message = session.createBlobMessage(file); + + producer.send(message); + Thread.sleep(1000); + + // check message send + Message msg = consumer.receive(1000); + assertTrue(msg instanceof ActiveMQBlobMessage); + + InputStream input = ((ActiveMQBlobMessage) msg).getInputStream(); + StringBuilder b = new StringBuilder(); + int i = input.read(); + while (i != -1) { + b.append((char) i); + i = input.read(); + } + input.close(); + File uploaded = new File(tmpDir, msg.getJMSMessageID().toString().replace(":", "_")); + assertEquals(content, b.toString()); + assertTrue(uploaded.exists()); + ((ActiveMQBlobMessage)msg).deleteFile(); + assertFalse(uploaded.exists()); + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.stop(); + } + super.tearDown(); + + IOHelper.deleteFile(new File(tmpDir)); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/AMQ4351Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/AMQ4351Test.java new file mode 100644 index 0000000000..e810f920de --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/AMQ4351Test.java @@ -0,0 +1,260 @@ +/** + * 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.broker; + +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.*; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Implements the test case attached to: + * https://issues.apache.org/jira/browse/AMQ-4351 + * + * This version avoids the spring deps. + */ +public class AMQ4351Test extends BrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4351Test.class); + + public static Test suite() { + return suite(AMQ4351Test.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + + // Lets clean up often. + broker.setOfflineDurableSubscriberTaskSchedule(500); + broker.setOfflineDurableSubscriberTimeout(2000); // lets delete durable subs much faster. + + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + + jdbc.deleteAllMessages(); + broker.setPersistenceAdapter(jdbc); + return broker; + } + + ActiveMQConnectionFactory connectionFactory; + ActiveMQTopic destination = new ActiveMQTopic("TEST"); + + @Override + protected void setUp() throws Exception { + super.setUp(); + connectionFactory = new ActiveMQConnectionFactory(broker.getVmConnectorURI()); + } + + class ProducingClient implements Runnable { + final AtomicLong size = new AtomicLong(); + final AtomicBoolean done = new AtomicBoolean(); + CountDownLatch doneLatch = new CountDownLatch(1); + + Connection connection; + Session session; + MessageProducer producer; + + ProducingClient() throws JMSException { + connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(destination); + } + + private void sendMessage() { + try { + producer.send(session.createTextMessage("Test")); + long i = size.incrementAndGet(); + if( (i % 1000) == 0 ) { + LOG.info("produced " + i + "."); + } + } catch (JMSException e) { + e.printStackTrace(); + } + } + + public void start() { + new Thread(this, "ProducingClient").start(); + } + + public void stop() throws InterruptedException { + done.set(true); + if( !doneLatch.await(20, TimeUnit.MILLISECONDS) ) { + try { + connection.close(); + doneLatch.await(); + } catch (JMSException e) { + } + } + } + + @Override + public void run() { + try { + try { + while (!done.get()) { + sendMessage(); + Thread.sleep(10); + } + } finally { + connection.close(); + } + } catch (Exception e) { + e.printStackTrace(); + done.set(true); + } finally { + doneLatch.countDown(); + } + } + } + + class ConsumingClient implements Runnable { + final String name; + final AtomicLong size = new AtomicLong(); + final AtomicBoolean done = new AtomicBoolean(); + CountDownLatch doneLatch = new CountDownLatch(1); + CountDownLatch started; + CountDownLatch finished; + + + public ConsumingClient(String name, CountDownLatch started, CountDownLatch finished) { + this.name = name; + this.started = started; + this.finished = finished; + } + + public void start() { + LOG.info("Starting JMS listener " + name); + new Thread(this, "ConsumingClient: "+name).start(); + } + + public void stopAsync() { + finished.countDown(); + done.set(true); + } + + public void stop() throws InterruptedException { + stopAsync(); + doneLatch.await(); + } + + @Override + public void run() { + try { + Connection connection = connectionFactory.createConnection(); + connection.setClientID(name); + connection.start(); + try { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createDurableSubscriber(destination, name, null, false); + started.countDown(); + while( !done.get() ) { + Message msg = consumer.receive(100); + if(msg!=null ) { + size.incrementAndGet(); + session.commit(); + } + } + } finally { + connection.close(); + LOG.info("Stopped JMS listener " + name); + } + } catch (Exception e) { + e.printStackTrace(); + done.set(true); + } finally { + doneLatch.countDown(); + } + } + + } + + public void testAMQ4351() throws InterruptedException, JMSException { + LOG.info("Start test."); + int subs = 100; + CountDownLatch startedLatch = new CountDownLatch(subs - 1); + CountDownLatch shutdownLatch = new CountDownLatch(subs - 4); + + + ProducingClient producer = new ProducingClient(); + ConsumingClient listener1 = new ConsumingClient("subscriber-1", startedLatch, shutdownLatch); + ConsumingClient listener2 = new ConsumingClient("subscriber-2", startedLatch, shutdownLatch); + ConsumingClient listener3 = new ConsumingClient("subscriber-3", startedLatch, shutdownLatch); + try { + + listener1.start(); + listener2.start(); + listener3.start(); + + List subscribers = new ArrayList(subs); + for (int i = 4; i < subs; i++) { + ConsumingClient client = new ConsumingClient("subscriber-" + i, startedLatch, shutdownLatch); + subscribers.add(client); + client.start(); + } + startedLatch.await(10, TimeUnit.SECONDS); + + LOG.info("All subscribers started."); + producer.sendMessage(); + + LOG.info("Stopping 97 subscribers...."); + for (ConsumingClient client : subscribers) { + client.stopAsync(); + } + shutdownLatch.await(10, TimeUnit.SECONDS); + + // Start producing messages for 10 minutes, at high rate + LOG.info("Starting mass message producer..."); + producer.start(); + + long lastSize = listener1.size.get(); + for( int i=0 ; i < 10; i++ ) { + Thread.sleep(1000); + long size = listener1.size.get(); + LOG.info("Listener 1: consumed: "+(size - lastSize)); + assertTrue( size > lastSize ); + lastSize = size; + } + } finally { + LOG.info("Stopping clients"); + listener1.stop(); + listener2.stop(); + listener3.stop(); + producer.stop(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerBenchmark.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerBenchmark.java new file mode 100644 index 0000000000..3e154f9a9a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerBenchmark.java @@ -0,0 +1,193 @@ +/** + * 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.broker; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicInteger; + +import junit.framework.Test; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * BrokerBenchmark is used to get an idea of the raw performance of a broker. + * Since the broker data structures using in message dispatching are under high + * contention from client requests, it's performance should be monitored closely + * since it typically is the biggest bottleneck in a high performance messaging + * fabric. The benchmarks are run under all the following combinations options: + * Queue vs. Topic, 1 vs. 10 producer threads, 1 vs. 10 consumer threads, and + * Persistent vs. Non-Persistent messages. Message Acking uses client ack style + * batch acking since that typically has the best ack performance. + * + * + */ +public class BrokerBenchmark extends BrokerTestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(BrokerBenchmark.class); + + public int produceCount = Integer.parseInt(System.getProperty("PRODUCE_COUNT", "10000")); + public ActiveMQDestination destination; + public int prodcuerCount; + public int consumerCount; + public boolean deliveryMode; + + public void initCombosForTestPerformance() { + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST")}); + addCombinationValues("PRODUCER_COUNT", new Object[] {new Integer("1"), new Integer("10")}); + addCombinationValues("CONSUMER_COUNT", new Object[] {new Integer("1"), new Integer("10")}); + addCombinationValues("CONSUMER_COUNT", new Object[] {new Integer("1"), new Integer("10")}); + addCombinationValues("deliveryMode", new Object[] {Boolean.TRUE}); + } + + public void testPerformance() throws Exception { + + LOG.info("Running Benchmark for destination=" + destination + ", producers=" + prodcuerCount + ", consumers=" + consumerCount + ", deliveryMode=" + deliveryMode); + final int consumeCount = destination.isTopic() ? consumerCount * produceCount : produceCount; + + final Semaphore consumersStarted = new Semaphore(1 - consumerCount); + final Semaphore producersFinished = new Semaphore(1 - prodcuerCount); + final Semaphore consumersFinished = new Semaphore(1 - consumerCount); + final ProgressPrinter printer = new ProgressPrinter(produceCount + consumeCount, 10); + + // Start a producer and consumer + + profilerPause("Benchmark ready. Start profiler "); + + long start = System.currentTimeMillis(); + + final AtomicInteger receiveCounter = new AtomicInteger(0); + for (int i = 0; i < consumerCount; i++) { + new Thread() { + public void run() { + try { + + // Consume the messages + StubConnection connection = new StubConnection(broker); + ConnectionInfo connectionInfo = createConnectionInfo(); + connection.send(connectionInfo); + + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1000); + connection.send(sessionInfo); + connection.send(consumerInfo); + + consumersStarted.release(); + + while (receiveCounter.get() < consumeCount) { + + int counter = 0; + // Get a least 1 message. + Message msg = receiveMessage(connection, 2000); + if (msg != null) { + printer.increment(); + receiveCounter.incrementAndGet(); + + counter++; + + // Try to piggy back a few extra message acks if + // they are ready. + Message extra = null; + while ((extra = receiveMessage(connection, 0)) != null) { + msg = extra; + printer.increment(); + receiveCounter.incrementAndGet(); + counter++; + } + } + + if (msg != null) { + connection.send(createAck(consumerInfo, msg, counter, MessageAck.STANDARD_ACK_TYPE)); + } else if (receiveCounter.get() < consumeCount) { + LOG.info("Consumer stall, waiting for message #" + receiveCounter.get() + 1); + } + } + + connection.send(closeConsumerInfo(consumerInfo)); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + consumersFinished.release(); + } + } + + }.start(); + } + + // Make sure that the consumers are started first to avoid sending + // messages + // before a topic is subscribed so that those messages are not missed. + consumersStarted.acquire(); + + // Send the messages in an async thread. + for (int i = 0; i < prodcuerCount; i++) { + new Thread() { + public void run() { + try { + StubConnection connection = new StubConnection(broker); + ConnectionInfo connectionInfo = createConnectionInfo(); + connection.send(connectionInfo); + + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < produceCount / prodcuerCount; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(deliveryMode); + message.setResponseRequired(false); + connection.send(message); + printer.increment(); + } + } catch (Throwable e) { + e.printStackTrace(); + } finally { + producersFinished.release(); + } + }; + }.start(); + } + + producersFinished.acquire(); + long end1 = System.currentTimeMillis(); + consumersFinished.acquire(); + long end2 = System.currentTimeMillis(); + + LOG.info("Results for destination=" + destination + ", producers=" + prodcuerCount + ", consumers=" + consumerCount + ", deliveryMode=" + deliveryMode); + LOG.info("Produced at messages/sec: " + (produceCount * 1000.0 / (end1 - start))); + LOG.info("Consumed at messages/sec: " + (consumeCount * 1000.0 / (end2 - start))); + profilerPause("Benchmark done. Stop profiler "); + } + + public static Test suite() { + return suite(BrokerBenchmark.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerRedeliveryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerRedeliveryTest.java new file mode 100644 index 0000000000..1fc7a6aeb2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerRedeliveryTest.java @@ -0,0 +1,185 @@ +/** + * 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.broker; + +import java.util.concurrent.TimeUnit; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.broker.region.policy.RedeliveryPolicyMap; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.broker.util.RedeliveryPlugin; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BrokerRedeliveryTest extends org.apache.activemq.TestSupport { + + static final Logger LOG = LoggerFactory.getLogger(BrokerRedeliveryTest.class); + BrokerService broker = null; + + final ActiveMQQueue destination = new ActiveMQQueue("Redelivery"); + final String data = "hi"; + final long redeliveryDelayMillis = 2000; + long initialRedeliveryDelayMillis = 4000; + int maxBrokerRedeliveries = 2; + + public void testScheduledRedelivery() throws Exception { + doTestScheduledRedelivery(maxBrokerRedeliveries, true); + } + + public void testInfiniteRedelivery() throws Exception { + initialRedeliveryDelayMillis = redeliveryDelayMillis; + maxBrokerRedeliveries = RedeliveryPolicy.NO_MAXIMUM_REDELIVERIES; + doTestScheduledRedelivery(RedeliveryPolicy.DEFAULT_MAXIMUM_REDELIVERIES + 1, false); + } + + public void doTestScheduledRedelivery(int maxBrokerRedeliveriesToValidate, boolean validateDLQ) throws Exception { + + startBroker(true); + sendMessage(0); + + ActiveMQConnection consumerConnection = (ActiveMQConnection) createConnection(); + RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); + redeliveryPolicy.setInitialRedeliveryDelay(0); + redeliveryPolicy.setMaximumRedeliveries(0); + consumerConnection.setRedeliveryPolicy(redeliveryPolicy); + consumerConnection.start(); + Session consumerSession = consumerConnection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = consumerSession.createConsumer(destination); + Message message = consumer.receive(1000); + assertNotNull("got message", message); + LOG.info("got: " + message); + consumerSession.rollback(); + + for (int i=0;i 0) { + producer.setTimeToLive(timeToLive); + } + Message message = producerSession.createMessage(); + message.setStringProperty("data", data); + producer.send(message); + producerConnection.close(); + } + + private void startBroker(boolean deleteMessages) throws Exception { + broker = new BrokerService(); + broker.setSchedulerSupport(true); + + + RedeliveryPlugin redeliveryPlugin = new RedeliveryPlugin(); + + RedeliveryPolicy brokerRedeliveryPolicy = new RedeliveryPolicy(); + brokerRedeliveryPolicy.setRedeliveryDelay(redeliveryDelayMillis); + brokerRedeliveryPolicy.setInitialRedeliveryDelay(initialRedeliveryDelayMillis); + brokerRedeliveryPolicy.setMaximumRedeliveries(maxBrokerRedeliveries); + + RedeliveryPolicyMap redeliveryPolicyMap = new RedeliveryPolicyMap(); + redeliveryPolicyMap.setDefaultEntry(brokerRedeliveryPolicy); + redeliveryPlugin.setRedeliveryPolicyMap(redeliveryPolicyMap); + + broker.setPlugins(new BrokerPlugin[]{redeliveryPlugin}); + + if (deleteMessages) { + broker.setDeleteAllMessagesOnStartup(true); + } + broker.start(); + } + + + private void stopBroker() throws Exception { + if (broker != null) + broker.stop(); + broker = null; + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost"); + } + + @Override + protected void tearDown() throws Exception { + stopBroker(); + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerRestartTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerRestartTestSupport.java new file mode 100644 index 0000000000..c4e3848803 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerRestartTestSupport.java @@ -0,0 +1,67 @@ +/** + * 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.broker; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; + +import org.apache.activemq.util.IOHelper; + +public class BrokerRestartTestSupport extends BrokerTestSupport { + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + File dir = broker.getBrokerDataDirectory(); + if (dir != null) { + IOHelper.deleteChildren(dir); + } + broker.setDeleteAllMessagesOnStartup(true); + configureBroker(broker); + return broker; + } + + /** + * @return + * @throws Exception + */ + protected BrokerService createRestartedBroker() throws Exception { + BrokerService broker = new BrokerService(); + configureBroker(broker); + return broker; + } + + protected void configureBroker(BrokerService broker) throws Exception { + broker.setDestinationPolicy(policyMap); + } + + /** + * Simulates a broker restart. The memory based persistence adapter is + * reused so that it does not "loose" it's "persistent" messages. + * + * @throws IOException + * @throws URISyntaxException + */ + protected void restartBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + broker = createRestartedBroker(); + broker.start(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerServiceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerServiceTest.java new file mode 100644 index 0000000000..9d55d04d48 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerServiceTest.java @@ -0,0 +1,84 @@ +/** + * 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.broker; + +import junit.framework.TestCase; +import org.apache.activemq.network.NetworkConnector; + +/** + * Tests for the BrokerService class + * + * @author chirino + */ +public class BrokerServiceTest extends TestCase { + + public void testAddRemoveTransportsWithJMX() throws Exception { + BrokerService service = new BrokerService(); + service.setUseJmx(true); + service.setPersistent(false); + TransportConnector connector = service.addConnector("tcp://localhost:0"); + service.start(); + + service.removeConnector(connector); + connector.stop(); + service.stop(); + } + + public void testAddRemoveTransportsWithoutJMX() throws Exception { + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + TransportConnector connector = service.addConnector("tcp://localhost:0"); + service.start(); + + service.removeConnector(connector); + connector.stop(); + service.stop(); + } + + public void testAddRemoveNetworkWithJMX() throws Exception { + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(true); + NetworkConnector connector = service.addNetworkConnector("multicast://default?group=group-"+System.currentTimeMillis()); + service.start(); + + service.removeNetworkConnector(connector); + connector.stop(); + service.stop(); + } + + public void testAddRemoveNetworkWithoutJMX() throws Exception { + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + NetworkConnector connector = service.addNetworkConnector("multicast://default?group=group-"+System.currentTimeMillis()); + service.start(); + + service.removeNetworkConnector(connector); + connector.stop(); + service.stop(); + } + + public void testSystemUsage() + { + BrokerService service = new BrokerService(); + assertEquals( 1024 * 1024 * 1024, service.getSystemUsage().getMemoryUsage().getLimit() ); + assertEquals( 1024L * 1024 * 1024 * 50, service.getSystemUsage().getTempUsage().getLimit() ); + assertEquals( 1024L * 1024 * 1024 * 100, service.getSystemUsage().getStoreUsage().getLimit() ); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerTest.java new file mode 100644 index 0000000000..2facb98f6f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerTest.java @@ -0,0 +1,1759 @@ +/** + * 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.broker; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.LocalTransactionId; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; + +public class BrokerTest extends BrokerTestSupport { + + public ActiveMQDestination destination; + public int deliveryMode; + public int prefetch; + public byte destinationType; + public boolean durableConsumer; + protected static final int MAX_NULL_WAIT=500; + + public void initCombosForTestQueueOnlyOnceDeliveryWith2Consumers() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + } + + public void testQueueOnlyOnceDeliveryWith2Consumers() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(1); + connection1.request(consumerInfo1); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(1); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + // Send the messages + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + + for (int i = 0; i < 2; i++) { + Message m1 = receiveMessage(connection1); + Message m2 = receiveMessage(connection2); + + assertNotNull("m1 is null for index: " + i, m1); + assertNotNull("m2 is null for index: " + i, m2); + + assertNotSame(m1.getMessageId(), m2.getMessageId()); + connection1.send(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + connection2.send(createAck(consumerInfo2, m2, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + assertNoMessagesLeft(connection1); + assertNoMessagesLeft(connection2); + } + + public void initCombosForTestQueueBrowserWith2Consumers() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + } + + public void testQueueBrowserWith2Consumers() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(10); + connection1.request(consumerInfo1); + + // Send the messages + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + //as the messages are sent async - need to synchronize the last + //one to ensure they arrive in the order we want + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + + // Setup a second connection with a queue browser. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(1); + consumerInfo2.setBrowser(true); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + List messages = new ArrayList(); + + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull("m1 is null for index: " + i, m1); + messages.add(m1); + } + + for (int i = 0; i < 4; i++) { + Message m1 = messages.get(i); + Message m2 = receiveMessage(connection2); + assertNotNull("m2 is null for index: " + i, m2); + assertEquals(m1.getMessageId(), m2.getMessageId()); + connection2.send(createAck(consumerInfo2, m2, 1, MessageAck.DELIVERED_ACK_TYPE)); + } + + assertNoMessagesLeft(connection1); + assertNoMessagesLeft(connection2); + } + + + /* + * change the order of the above test + */ + public void testQueueBrowserWith2ConsumersBrowseFirst() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + deliveryMode = DeliveryMode.NON_PERSISTENT; + + + // Setup a second connection with a queue browser. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(10); + consumerInfo2.setBrowser(true); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(10); + connection1.request(consumerInfo1); + + // Send the messages + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + //as the messages are sent async - need to synchronize the last + //one to ensure they arrive in the order we want + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + + + List messages = new ArrayList(); + + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull("m1 is null for index: " + i, m1); + messages.add(m1); + } + + // no messages present in queue browser as there were no messages when it + // was created + assertNoMessagesLeft(connection1); + assertNoMessagesLeft(connection2); + } + + public void testQueueBrowserWith2ConsumersInterleaved() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + deliveryMode = DeliveryMode.NON_PERSISTENT; + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(10); + connection1.request(consumerInfo1); + + // Send the messages + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + + // Setup a second connection with a queue browser. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(1); + consumerInfo2.setBrowser(true); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + //as the messages are sent async - need to synchronize the last + //one to ensure they arrive in the order we want + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + + + List messages = new ArrayList(); + + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull("m1 is null for index: " + i, m1); + messages.add(m1); + } + + for (int i = 0; i < 4; i++) { + Message m1 = messages.get(i); + Message m2 = receiveMessage(connection2); + assertNotNull("m2 is null for index: " + i, m2); + assertEquals(m1.getMessageId(), m2.getMessageId()); + connection2.send(createAck(consumerInfo2, m2, 1, MessageAck.DELIVERED_ACK_TYPE)); + } + + assertNoMessagesLeft(connection1); + assertNoMessagesLeft(connection2); + } + + + public void initCombosForTestConsumerPrefetchAndStandardAck() { + addCombinationValues("deliveryMode", new Object[] { + // Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testConsumerPrefetchAndStandardAck() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1); + connection.send(consumerInfo); + + // Send 3 messages to the broker. + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.request(createMessage(producerInfo, destination, deliveryMode)); + + // Make sure only 1 message was delivered. + Message m1 = receiveMessage(connection); + assertNotNull(m1); + assertNoMessagesLeft(connection); + + // Acknowledge the first message. This should cause the next message to + // get dispatched. + connection.send(createAck(consumerInfo, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + + Message m2 = receiveMessage(connection); + assertNotNull(m2); + connection.send(createAck(consumerInfo, m2, 1, MessageAck.STANDARD_ACK_TYPE)); + + Message m3 = receiveMessage(connection); + assertNotNull(m3); + connection.send(createAck(consumerInfo, m3, 1, MessageAck.STANDARD_ACK_TYPE)); + + connection.send(closeConnectionInfo(connectionInfo)); + } + + public void initCombosForTestTransactedAckWithPrefetchOfOne() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testTransactedAckWithPrefetchOfOne() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(1); + connection1.send(consumerInfo1); + + // Send the messages + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo1, destination, deliveryMode); + connection1.send(message); + } + + + + // Now get the messages. + for (int i = 0; i < 4; i++) { + // Begin the transaction. + LocalTransactionId txid = createLocalTransaction(sessionInfo1); + connection1.send(createBeginTransaction(connectionInfo1, txid)); + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + MessageAck ack = createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection1.send(ack); + // Commit the transaction. + connection1.send(createCommitTransaction1Phase(connectionInfo1, txid)); + } + assertNoMessagesLeft(connection1); + } + + public void initCombosForTestTransactedSend() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testTransactedSend() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Begin the transaction. + LocalTransactionId txid = createLocalTransaction(sessionInfo1); + connection1.send(createBeginTransaction(connectionInfo1, txid)); + + // Send the messages + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo1, destination, deliveryMode); + message.setTransactionId(txid); + connection1.request(message); + } + + // The point of this test is that message should not be delivered until + // send is committed. + assertNull(receiveMessage(connection1,MAX_NULL_WAIT)); + + // Commit the transaction. + connection1.send(createCommitTransaction1Phase(connectionInfo1, txid)); + + // Now get the messages. + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + } + + assertNoMessagesLeft(connection1); + } + + public void initCombosForTestQueueTransactedAck() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE)}); + } + + public void testQueueTransactedAck() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Send the messages + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo1, destination, deliveryMode); + connection1.send(message); + } + + // Begin the transaction. + LocalTransactionId txid = createLocalTransaction(sessionInfo1); + connection1.send(createBeginTransaction(connectionInfo1, txid)); + + // Acknowledge the first 2 messages. + for (int i = 0; i < 2; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull("m1 is null for index: " + i, m1); + MessageAck ack = createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection1.request(ack); + } + + // Commit the transaction. + connection1.send(createCommitTransaction1Phase(connectionInfo1, txid)); + + // The queue should now only have the remaining 2 messages + assertEquals(2, countMessagesInQueue(connection1, connectionInfo1, destination)); + } + + public void initCombosForTestConsumerCloseCausesRedelivery() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST")}); + } + + public void testConsumerCloseCausesRedelivery() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + connection1.request(consumerInfo1); + + // Send the messages + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + + // Receive the messages. + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull("m1 is null for index: " + i, m1); + assertFalse(m1.isRedelivered()); + } + + // Close the consumer without acking.. this should cause re-delivery of + // the messages. + connection1.send(consumerInfo1.createRemoveCommand()); + + // Create another consumer that should get the messages again. + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo1, destination); + consumerInfo2.setPrefetchSize(100); + connection1.request(consumerInfo2); + + // Receive the messages. + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull("m1 is null for index: " + i, m1); + assertTrue(m1.isRedelivered()); + } + assertNoMessagesLeft(connection1); + + } + + public void testTopicDurableSubscriptionCanBeRestored() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + connectionInfo1.setClientId("clientid1"); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + consumerInfo1.setSubscriptionName("test"); + connection1.send(consumerInfo1); + + // Send the messages + connection1.send(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + connection1.send(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + connection1.send(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + connection1.request(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + + // Get the messages + Message m = null; + for (int i = 0; i < 2; i++) { + m = receiveMessage(connection1); + assertNotNull(m); + } + // Ack the last message. + connection1.send(createAck(consumerInfo1, m, 2, MessageAck.STANDARD_ACK_TYPE)); + // Close the connection. + connection1.request(closeConnectionInfo(connectionInfo1)); + connection1.stop(); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + connectionInfo2.setClientId("clientid1"); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(100); + consumerInfo2.setSubscriptionName("test"); + + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(consumerInfo2); + + // Get the rest of the messages + for (int i = 0; i < 2; i++) { + Message m1 = receiveMessage(connection2); + assertNotNull("m1 is null for index: " + i, m1); + } + assertNoMessagesLeft(connection2); + } + + public void initCombosForTestGroupedMessagesDeliveredToOnlyOneConsumer() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + } + + public void testGroupedMessagesDeliveredToOnlyOneConsumer() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(1); + connection1.send(consumerInfo1); + + // Send the messages. + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination, deliveryMode); + message.setGroupID("TEST-GROUP"); + message.setGroupSequence(i + 1); + connection1.request(message); + } + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(1); + connection2.send(consumerInfo2); + + // All the messages should have been sent down connection 1.. just get + // the first 3 + for (int i = 0; i < 3; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull("m1 is null for index: " + i, m1); + connection1.send(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + // Close the first consumer. + connection1.request(closeConsumerInfo(consumerInfo1)); + + // The last messages should now go the the second consumer. + for (int i = 0; i < 1; i++) { + Message m1 = receiveMessage(connection2); + assertNotNull("m1 is null for index: " + i, m1); + connection2.request(createAck(consumerInfo2, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + assertNoMessagesLeft(connection2); + } + + public void initCombosForTestTopicConsumerOnlySeeMessagesAfterCreation() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("durableConsumer", new Object[] {Boolean.TRUE, Boolean.FALSE}); + } + + public void testTopicConsumerOnlySeeMessagesAfterCreation() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + connectionInfo1.setClientId("A"); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + // Send the 1st message + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + + // Create the durable subscription. + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + if (durableConsumer) { + consumerInfo1.setSubscriptionName("test"); + } + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + Message m = createMessage(producerInfo1, destination, deliveryMode); + connection1.send(m); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + + // Subscription should skip over the first message + Message m2 = receiveMessage(connection1); + assertNotNull(m2); + assertEquals(m.getMessageId(), m2.getMessageId()); + m2 = receiveMessage(connection1); + assertNotNull(m2); + + assertNoMessagesLeft(connection1); + } + + public void initCombosForTestTopicRetroactiveConsumerSeeMessagesBeforeCreation() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("durableConsumer", new Object[] {Boolean.TRUE, Boolean.FALSE}); + } + + public void testTopicRetroactiveConsumerSeeMessagesBeforeCreation() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + connectionInfo1.setClientId("A"); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + // Send the messages + Message m = createMessage(producerInfo1, destination, deliveryMode); + connection1.send(m); + + // Create the durable subscription. + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + if (durableConsumer) { + consumerInfo1.setSubscriptionName("test"); + } + consumerInfo1.setPrefetchSize(100); + consumerInfo1.setRetroactive(true); + connection1.send(consumerInfo1); + + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.request(createMessage(producerInfo1, destination, deliveryMode)); + + // the behavior is VERY dependent on the recovery policy used. + // But the default broker settings try to make it as consistent as + // possible + + // Subscription should see all messages sent. + Message m2 = receiveMessage(connection1); + assertNotNull(m2); + assertEquals(m.getMessageId(), m2.getMessageId()); + for (int i = 0; i < 2; i++) { + m2 = receiveMessage(connection1); + assertNotNull(m2); + } + + assertNoMessagesLeft(connection1); + } + + // + // TODO: need to reimplement this since we don't fail when we send to a + // non-existant + // destination. But if we can access the Region directly then we should be + // able to + // check that if the destination was removed. + // + // public void initCombosForTestTempDestinationsRemovedOnConnectionClose() { + // addCombinationValues( "deliveryMode", new Object[]{ + // Integer.valueOf(DeliveryMode.NON_PERSISTENT), + // Integer.valueOf(DeliveryMode.PERSISTENT)} ); + // addCombinationValues( "destinationType", new Object[]{ + // Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + // Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)} ); + // } + // + // public void testTempDestinationsRemovedOnConnectionClose() throws + // Exception { + // + // // Setup a first connection + // StubConnection connection1 = createConnection(); + // ConnectionInfo connectionInfo1 = createConnectionInfo(); + // SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + // ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + // connection1.send(connectionInfo1); + // connection1.send(sessionInfo1); + // connection1.send(producerInfo1); + // + // destination = createDestinationInfo(connection1, connectionInfo1, + // destinationType); + // + // StubConnection connection2 = createConnection(); + // ConnectionInfo connectionInfo2 = createConnectionInfo(); + // SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + // ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + // connection2.send(connectionInfo2); + // connection2.send(sessionInfo2); + // connection2.send(producerInfo2); + // + // // Send from connection2 to connection1's temp destination. Should + // succeed. + // connection2.send(createMessage(producerInfo2, destination, + // deliveryMode)); + // + // // Close connection 1 + // connection1.request(closeConnectionInfo(connectionInfo1)); + // + // try { + // // Send from connection2 to connection1's temp destination. Should not + // succeed. + // connection2.request(createMessage(producerInfo2, destination, + // deliveryMode)); + // fail("Expected JMSException."); + // } catch ( JMSException success ) { + // } + // + // } + + // public void initCombosForTestTempDestinationsAreNotAutoCreated() { + // addCombinationValues( "deliveryMode", new Object[]{ + // Integer.valueOf(DeliveryMode.NON_PERSISTENT), + // Integer.valueOf(DeliveryMode.PERSISTENT)} ); + // addCombinationValues( "destinationType", new Object[]{ + // Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + // Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)} ); + // } + // + // + + // We create temp destination on demand now so this test case is no longer + // valid. + // + // public void testTempDestinationsAreNotAutoCreated() throws Exception { + // + // // Setup a first connection + // StubConnection connection1 = createConnection(); + // ConnectionInfo connectionInfo1 = createConnectionInfo(); + // SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + // ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + // connection1.send(connectionInfo1); + // connection1.send(sessionInfo1); + // connection1.send(producerInfo1); + // + // destination = + // ActiveMQDestination.createDestination(connectionInfo1.getConnectionId()+":1", + // destinationType); + // + // // Should not be able to send to a non-existant temp destination. + // try { + // connection1.request(createMessage(producerInfo1, destination, + // deliveryMode)); + // fail("Expected JMSException."); + // } catch ( JMSException success ) { + // } + // + // } + + + public void initCombosForTestExclusiveQueueDeliversToOnlyOneConsumer() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + } + + public void testExclusiveQueueDeliversToOnlyOneConsumer() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(1); + consumerInfo1.setExclusive(true); + connection1.send(consumerInfo1); + + // Send a message.. this should make consumer 1 the exclusive owner. + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(1); + consumerInfo2.setExclusive(true); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + // Second message should go to consumer 1 even though consumer 2 is + // ready + // for dispatch. + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + + // Acknowledge the first 2 messages + for (int i = 0; i < 2; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + connection1.send(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + // Close the first consumer. + connection1.send(closeConsumerInfo(consumerInfo1)); + + // The last two messages should now go the the second consumer. + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + + for (int i = 0; i < 2; i++) { + Message m1 = receiveMessage(connection2); + assertNotNull(m1); + connection2.send(createAck(consumerInfo2, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + assertNoMessagesLeft(connection2); + } + + public void initCombosForTestWildcardConsume() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testWildcardConsume() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + // setup the wildcard consumer. + ActiveMQDestination compositeDestination = ActiveMQDestination.createDestination("WILD.*.TEST", + destinationType); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, compositeDestination); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // These two message should NOT match the wild card. + connection1.send(createMessage(producerInfo1, ActiveMQDestination.createDestination("WILD.CARD", + destinationType), + deliveryMode)); + connection1.send(createMessage(producerInfo1, ActiveMQDestination.createDestination("WILD.TEST", + destinationType), + deliveryMode)); + + // These two message should match the wild card. + ActiveMQDestination d1 = ActiveMQDestination.createDestination("WILD.CARD.TEST", destinationType); + connection1.send(createMessage(producerInfo1, d1, deliveryMode)); + + Message m = receiveMessage(connection1); + assertNotNull(m); + assertEquals(d1, m.getDestination()); + + ActiveMQDestination d2 = ActiveMQDestination.createDestination("WILD.FOO.TEST", destinationType); + connection1.request(createMessage(producerInfo1, d2, deliveryMode)); + m = receiveMessage(connection1); + assertNotNull(m); + assertEquals(d2, m.getDestination()); + + assertNoMessagesLeft(connection1); + connection1.send(closeConnectionInfo(connectionInfo1)); + } + + public void initCombosForTestCompositeConsume() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testCompositeConsume() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + // setup the composite consumer. + ActiveMQDestination compositeDestination = ActiveMQDestination.createDestination("A,B", + destinationType); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, compositeDestination); + consumerInfo1.setRetroactive(true); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Publish to the two destinations + ActiveMQDestination destinationA = ActiveMQDestination.createDestination("A", destinationType); + ActiveMQDestination destinationB = ActiveMQDestination.createDestination("B", destinationType); + + // Send a message to each destination . + connection1.send(createMessage(producerInfo1, destinationA, deliveryMode)); + connection1.send(createMessage(producerInfo1, destinationB, deliveryMode)); + + // The consumer should get both messages. + for (int i = 0; i < 2; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + } + + assertNoMessagesLeft(connection1); + connection1.send(closeConnectionInfo(connectionInfo1)); + } + + public void initCombosForTestCompositeSend() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testCompositeSend() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + ActiveMQDestination destinationA = ActiveMQDestination.createDestination("A", destinationType); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destinationA); + consumerInfo1.setRetroactive(true); + consumerInfo1.setPrefetchSize(100); + connection1.request(consumerInfo1); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + + ActiveMQDestination destinationB = ActiveMQDestination.createDestination("B", destinationType); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destinationB); + consumerInfo2.setRetroactive(true); + consumerInfo2.setPrefetchSize(100); + connection2.request(consumerInfo2); + + // Send the messages to the composite destination. + ActiveMQDestination compositeDestination = ActiveMQDestination.createDestination("A,B", + destinationType); + for (int i = 0; i < 4; i++) { + connection1.request(createMessage(producerInfo1, compositeDestination, deliveryMode)); + } + + // The messages should have been delivered to both the A and B + // destination. + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + Message m2 = receiveMessage(connection2); + + assertNotNull(m1); + assertNotNull(m2); + + assertEquals(m1.getMessageId(), m2.getMessageId()); + assertEquals(compositeDestination, m1.getOriginalDestination()); + assertEquals(compositeDestination, m2.getOriginalDestination()); + + connection1.request(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + connection2.request(createAck(consumerInfo2, m2, 1, MessageAck.STANDARD_ACK_TYPE)); + + } + + assertNoMessagesLeft(connection1); + assertNoMessagesLeft(connection2); + + connection1.send(closeConnectionInfo(connectionInfo1)); + connection2.send(closeConnectionInfo(connectionInfo2)); + } + + public void initCombosForTestConnectionCloseCascades() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destination", new Object[] {new ActiveMQTopic("TEST"), + new ActiveMQQueue("TEST")}); + } + + public void testConnectionCloseCascades() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + consumerInfo1.setNoLocal(true); + connection1.request(consumerInfo1); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(producerInfo2); + + // Send the messages + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + connection1.send(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + // give the async ack a chance to perculate and validate all are currently consumed + Message msg = receiveMessage(connection1, MAX_NULL_WAIT); + assertNull("all messages were received " + msg, msg); + + // Close the connection, this should in turn close the consumer. + connection1.request(closeConnectionInfo(connectionInfo1)); + + // Send another message, connection1 should not get the message. + connection2.request(createMessage(producerInfo2, destination, deliveryMode)); + + assertNull("no message received", receiveMessage(connection1, MAX_NULL_WAIT)); + } + + public void initCombosForTestSessionCloseCascades() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destination", new Object[] {new ActiveMQTopic("TEST"), + new ActiveMQQueue("TEST")}); + } + + public void testSessionCloseCascades() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + consumerInfo1.setNoLocal(true); + connection1.request(consumerInfo1); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(producerInfo2); + + // Send the messages + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + connection1.send(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + // Close the session, this should in turn close the consumer. + connection1.request(closeSessionInfo(sessionInfo1)); + + // Send another message, connection1 should not get the message. + connection2.request(createMessage(producerInfo2, destination, deliveryMode)); + + Message msg = receiveMessage(connection1,MAX_NULL_WAIT); + assertNull("no message received from connection1 after session close", msg); + } + + public void initCombosForTestConsumerClose() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destination", new Object[] {new ActiveMQTopic("TEST"), + new ActiveMQQueue("TEST")}); + } + + public void testConsumerClose() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + consumerInfo1.setNoLocal(true); + connection1.request(consumerInfo1); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(producerInfo2); + + // Send the messages + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + connection2.send(createMessage(producerInfo2, destination, deliveryMode)); + + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + connection1.send(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + // give the async ack a chance to perculate and validate all are currently consumed + // use receive rather than poll as broker info is sent async and may still need to be dequeued + Message result = receiveMessage(connection1, MAX_NULL_WAIT); + assertNull("no more messages " + result, result); + + // Close the consumer. + connection1.request(closeConsumerInfo(consumerInfo1)); + + // Send another message, connection1 should not get the message. + connection2.request(createMessage(producerInfo2, destination, deliveryMode)); + + result = receiveMessage(connection1, MAX_NULL_WAIT); + assertNull("no message received after close " + result, result); + } + + public void initCombosForTestTopicNoLocal() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + } + + public void testTopicNoLocal() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setRetroactive(true); + consumerInfo1.setPrefetchSize(100); + consumerInfo1.setNoLocal(true); + connection1.send(consumerInfo1); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(producerInfo2); + + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setRetroactive(true); + consumerInfo2.setPrefetchSize(100); + consumerInfo2.setNoLocal(true); + connection2.send(consumerInfo2); + + // Send the messages + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + + // The 2nd connection should get the messages. + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection2); + assertNotNull(m1); + } + + // Send a message with the 2nd connection + Message message = createMessage(producerInfo2, destination, deliveryMode); + connection2.send(message); + + // The first connection should not see the initial 4 local messages sent + // but should + // see the messages from connection 2. + Message m = receiveMessage(connection1); + assertNotNull(m); + assertEquals(message.getMessageId(), m.getMessageId()); + + assertNoMessagesLeft(connection1); + assertNoMessagesLeft(connection2); + } + + public void initCombosForTopicDispatchIsBroadcast() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + } + + public void testTopicDispatchIsBroadcast() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setRetroactive(true); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setRetroactive(true); + consumerInfo2.setPrefetchSize(100); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(consumerInfo2); + + // Send the messages + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + connection1.send(createMessage(producerInfo1, destination, deliveryMode)); + + // Get the messages + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + m1 = receiveMessage(connection2); + assertNotNull(m1); + } + } + + public void initCombosForTestQueueDispatchedAreRedeliveredOnConsumerClose() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE)}); + } + + public void testQueueDispatchedAreRedeliveredOnConsumerClose() throws Exception { + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Send the messages + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + + // Get the messages + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertFalse(m1.isRedelivered()); + } + // Close the consumer without sending any ACKS. + connection1.send(closeConsumerInfo(consumerInfo1)); + + // Drain any in flight messages.. + while (connection1.getDispatchQueue().poll(0, TimeUnit.MILLISECONDS) != null) { + } + + // Add the second consumer + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo1, destination); + consumerInfo2.setPrefetchSize(100); + connection1.send(consumerInfo2); + + // Make sure the messages were re delivered to the 2nd consumer. + for (int i = 0; i < 4; i++) { + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertTrue(m1.isRedelivered()); + } + } + + public void initCombosForTestQueueBrowseMessages() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE)}); + } + + public void testQueueBrowseMessages() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + + // Use selector to skip first message. + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setBrowser(true); + connection.send(consumerInfo); + + for (int i = 0; i < 4; i++) { + Message m = receiveMessage(connection); + assertNotNull(m); + connection.send(createAck(consumerInfo, m, 1, MessageAck.DELIVERED_ACK_TYPE)); + } + + assertNoMessagesLeft(connection); + } + + public void initCombosForTestQueueSendThenAddConsumer() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE)}); + } + + public void testQueueSendThenAddConsumer() throws Exception { + + // Start a producer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + // Send a message to the broker. + connection.send(createMessage(producerInfo, destination, deliveryMode)); + + // Start the consumer + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Make sure the message was delivered. + Message m = receiveMessage(connection); + assertNotNull(m); + + } + + public void initCombosForTestQueueAckRemovesMessage() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE)}); + } + + public void testQueueAckRemovesMessage() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + Message message1 = createMessage(producerInfo, destination, deliveryMode); + Message message2 = createMessage(producerInfo, destination, deliveryMode); + connection.send(message1); + connection.send(message2); + + // Make sure the message was delivered. + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.request(consumerInfo); + Message m = receiveMessage(connection); + assertNotNull(m); + assertEquals(m.getMessageId(), message1.getMessageId()); + + assertTrue(countMessagesInQueue(connection, connectionInfo, destination) == 2); + connection.send(createAck(consumerInfo, m, 1, MessageAck.DELIVERED_ACK_TYPE)); + assertTrue(countMessagesInQueue(connection, connectionInfo, destination) == 2); + connection.send(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + assertTrue(countMessagesInQueue(connection, connectionInfo, destination) == 1); + + } + + public void initCombosForTestSelectorSkipsMessages() { + addCombinationValues("destination", new Object[] {new ActiveMQTopic("TEST_TOPIC"), + new ActiveMQQueue("TEST_QUEUE")}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testSelectorSkipsMessages() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSelector("JMSType='last'"); + connection.send(consumerInfo); + + Message message1 = createMessage(producerInfo, destination, deliveryMode); + message1.setType("first"); + Message message2 = createMessage(producerInfo, destination, deliveryMode); + message2.setType("last"); + connection.send(message1); + connection.send(message2); + + // Use selector to skip first message. + Message m = receiveMessage(connection); + assertNotNull(m); + assertEquals(m.getMessageId(), message2.getMessageId()); + connection.send(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + connection.send(closeConsumerInfo(consumerInfo)); + + assertNoMessagesLeft(connection); + } + + public void initCombosForTestAddConsumerThenSend() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testAddConsumerThenSend() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + connection.send(createMessage(producerInfo, destination, deliveryMode)); + + // Make sure the message was delivered. + Message m = receiveMessage(connection); + assertNotNull(m); + } + + public void initCombosForTestConsumerPrefetchAtOne() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testConsumerPrefetchAtOne() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1); + connection.send(consumerInfo); + + // Send 2 messages to the broker. + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + + // Make sure only 1 message was delivered. + Message m = receiveMessage(connection); + assertNotNull(m); + assertNoMessagesLeft(connection); + + } + + public void initCombosForTestConsumerPrefetchAtTwo() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testConsumerPrefetchAtTwo() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(2); + connection.send(consumerInfo); + + // Send 3 messages to the broker. + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + + // Make sure only 1 message was delivered. + Message m = receiveMessage(connection); + assertNotNull(m); + m = receiveMessage(connection); + assertNotNull(m); + assertNoMessagesLeft(connection); + + } + + public void initCombosForTestConsumerPrefetchAndDeliveredAck() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), + Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", + new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testConsumerPrefetchAndDeliveredAck() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1); + connection.request(consumerInfo); + + // Send 3 messages to the broker. + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.send(createMessage(producerInfo, destination, deliveryMode)); + connection.request(createMessage(producerInfo, destination, deliveryMode)); + + // Make sure only 1 message was delivered. + Message m1 = receiveMessage(connection); + assertNotNull(m1); + + assertNoMessagesLeft(connection); + + // Acknowledge the first message. This should cause the next message to + // get dispatched. + connection.request(createAck(consumerInfo, m1, 1, MessageAck.DELIVERED_ACK_TYPE)); + + Message m2 = receiveMessage(connection); + assertNotNull(m2); + connection.request(createAck(consumerInfo, m2, 1, MessageAck.DELIVERED_ACK_TYPE)); + + Message m3 = receiveMessage(connection); + assertNotNull(m3); + connection.request(createAck(consumerInfo, m3, 1, MessageAck.DELIVERED_ACK_TYPE)); + } + + public void testGetServices() throws Exception { + assertTrue(broker.getServices().length != 0); + } + + public static Test suite() { + return suite(BrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerTestSupport.java new file mode 100644 index 0000000000..5fa0620bad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/BrokerTestSupport.java @@ -0,0 +1,357 @@ +/** + * 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.broker; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.TimeUnit; + +import javax.jms.DeliveryMode; +import javax.jms.MessageNotWriteableException; + +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.FixedCountSubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.RoundRobinDispatchPolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.DestinationInfo; +import org.apache.activemq.command.LocalTransactionId; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatch; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.RemoveInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.command.TransactionInfo; +import org.apache.activemq.command.XATransactionId; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.usage.SystemUsage; + +public class BrokerTestSupport extends CombinationTestSupport { + + /** + * Setting this to false makes the test run faster but they may be less + * accurate. + */ + public static final boolean FAST_NO_MESSAGE_LEFT_ASSERT = System.getProperty("FAST_NO_MESSAGE_LEFT_ASSERT", "true").equals("true"); + + protected RegionBroker regionBroker; + public BrokerService broker; + protected long idGenerator; + protected int msgIdGenerator; + protected int txGenerator; + protected int tempDestGenerator; + public PersistenceAdapter persistenceAdapter; + + protected String queueName = "TEST"; + + protected int maxWait = 10000; + + protected SystemUsage memoryManager; + protected PolicyMap policyMap = new PolicyMap(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = createBroker(); + policyMap.setDefaultEntry(getDefaultPolicy()); + broker.setDestinationPolicy(policyMap); + broker.start(); + } + + protected PolicyEntry getDefaultPolicy() { + PolicyEntry policy = new PolicyEntry(); + policy.setDispatchPolicy(new RoundRobinDispatchPolicy()); + policy.setSubscriptionRecoveryPolicy(new FixedCountSubscriptionRecoveryPolicy()); + return policy; + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = BrokerFactory.createBroker(new URI("broker:()/localhost?persistent=false")); + return broker; + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + regionBroker = null; + persistenceAdapter = null; + memoryManager = null; + super.tearDown(); + } + + protected ConsumerInfo createConsumerInfo(SessionInfo sessionInfo, ActiveMQDestination destination) throws Exception { + ConsumerInfo info = new ConsumerInfo(sessionInfo, ++idGenerator); + info.setBrowser(false); + info.setDestination(destination); + info.setPrefetchSize(1000); + info.setDispatchAsync(false); + return info; + } + + protected RemoveInfo closeConsumerInfo(ConsumerInfo consumerInfo) { + return consumerInfo.createRemoveCommand(); + } + + protected ProducerInfo createProducerInfo(SessionInfo sessionInfo) throws Exception { + ProducerInfo info = new ProducerInfo(sessionInfo, ++idGenerator); + return info; + } + + protected SessionInfo createSessionInfo(ConnectionInfo connectionInfo) throws Exception { + SessionInfo info = new SessionInfo(connectionInfo, ++idGenerator); + return info; + } + + protected ConnectionInfo createConnectionInfo() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + info.setConnectionId(new ConnectionId("connection:" + (++idGenerator))); + info.setClientId(info.getConnectionId().getValue()); + return info; + } + + protected Message createMessage(ProducerInfo producerInfo, ActiveMQDestination destination) { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setMessageId(new MessageId(producerInfo, ++msgIdGenerator)); + message.setDestination(destination); + message.setPersistent(false); + try { + message.setText("Test Message Payload."); + } catch (MessageNotWriteableException e) { + } + return message; + } + + protected MessageAck createAck(ConsumerInfo consumerInfo, Message msg, int count, byte ackType) { + MessageAck ack = new MessageAck(); + ack.setAckType(ackType); + ack.setConsumerId(consumerInfo.getConsumerId()); + ack.setDestination(msg.getDestination()); + ack.setLastMessageId(msg.getMessageId()); + ack.setMessageCount(count); + return ack; + } + + protected void gc() { + regionBroker.gc(); + } + + protected void profilerPause(String prompt) throws IOException { + if (System.getProperty("profiler") != null) { + System.out.println(); + System.out.println(prompt + "> Press enter to continue: "); + while (System.in.read() != '\n') { + } + System.out.println(prompt + "> Done."); + } + } + + protected RemoveInfo closeConnectionInfo(ConnectionInfo info) { + return info.createRemoveCommand(); + } + + protected RemoveInfo closeSessionInfo(SessionInfo info) { + return info.createRemoveCommand(); + } + + protected RemoveInfo closeProducerInfo(ProducerInfo info) { + return info.createRemoveCommand(); + } + + protected Message createMessage(ProducerInfo producerInfo, ActiveMQDestination destination, int deliveryMode) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(deliveryMode == DeliveryMode.PERSISTENT); + return message; + } + + protected LocalTransactionId createLocalTransaction(SessionInfo info) { + LocalTransactionId id = new LocalTransactionId(info.getSessionId().getParentId(), ++txGenerator); + return id; + } + + protected XATransactionId createXATransaction(SessionInfo info) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + os.writeLong(++txGenerator); + os.close(); + byte[] bs = baos.toByteArray(); + + XATransactionId xid = new XATransactionId(); + xid.setBranchQualifier(bs); + xid.setGlobalTransactionId(bs); + xid.setFormatId(55); + return xid; + } + + protected TransactionInfo createBeginTransaction(ConnectionInfo connectionInfo, TransactionId txid) { + TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.BEGIN); + return info; + } + + protected TransactionInfo createPrepareTransaction(ConnectionInfo connectionInfo, TransactionId txid) { + TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.PREPARE); + return info; + } + + protected TransactionInfo createCommitTransaction1Phase(ConnectionInfo connectionInfo, TransactionId txid) { + TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.COMMIT_ONE_PHASE); + return info; + } + + protected TransactionInfo createCommitTransaction2Phase(ConnectionInfo connectionInfo, TransactionId txid) { + TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.COMMIT_TWO_PHASE); + return info; + } + + protected TransactionInfo createRollbackTransaction(ConnectionInfo connectionInfo, TransactionId txid) { + TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.ROLLBACK); + return info; + } + + protected int countMessagesInQueue(StubConnection connection, ConnectionInfo connectionInfo, ActiveMQDestination destination) throws Exception { + + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1); + consumerInfo.setBrowser(true); + connection.send(consumerInfo); + + ArrayList skipped = new ArrayList(); + + // Now get the messages. + Object m = connection.getDispatchQueue().poll(maxWait, TimeUnit.MILLISECONDS); + int i = 0; + while (m != null) { + if (m instanceof MessageDispatch && ((MessageDispatch)m).getConsumerId().equals(consumerInfo.getConsumerId())) { + MessageDispatch md = (MessageDispatch)m; + if (md.getMessage() != null) { + i++; + connection.send(createAck(consumerInfo, md.getMessage(), 1, MessageAck.STANDARD_ACK_TYPE)); + } else { + break; + } + } else { + skipped.add(m); + } + m = connection.getDispatchQueue().poll(maxWait, TimeUnit.MILLISECONDS); + } + + for (Iterator iter = skipped.iterator(); iter.hasNext();) { + connection.getDispatchQueue().put(iter.next()); + } + + connection.send(closeSessionInfo(sessionInfo)); + return i; + + } + + protected DestinationInfo createTempDestinationInfo(ConnectionInfo connectionInfo, byte destinationType) { + DestinationInfo info = new DestinationInfo(); + info.setConnectionId(connectionInfo.getConnectionId()); + info.setOperationType(DestinationInfo.ADD_OPERATION_TYPE); + info.setDestination(ActiveMQDestination.createDestination(info.getConnectionId() + ":" + (++tempDestGenerator), destinationType)); + return info; + } + + protected ActiveMQDestination createDestinationInfo(StubConnection connection, ConnectionInfo connectionInfo1, byte destinationType) throws Exception { + if ((destinationType & ActiveMQDestination.TEMP_MASK) != 0) { + DestinationInfo info = createTempDestinationInfo(connectionInfo1, destinationType); + connection.send(info); + return info.getDestination(); + } else { + return ActiveMQDestination.createDestination(queueName, destinationType); + } + } + + protected DestinationInfo closeDestinationInfo(DestinationInfo info) { + info.setOperationType(DestinationInfo.REMOVE_OPERATION_TYPE); + info.setTimeout(0); + return info; + } + + public static void recursiveDelete(File f) { + if (f.isDirectory()) { + File[] files = f.listFiles(); + for (int i = 0; i < files.length; i++) { + recursiveDelete(files[i]); + } + } + f.delete(); + } + + protected StubConnection createConnection() throws Exception { + return new StubConnection(broker); + } + + /** + * @param connection + * @return + * @throws InterruptedException + */ + public Message receiveMessage(StubConnection connection) throws InterruptedException { + return receiveMessage(connection, maxWait); + } + + public Message receiveMessage(StubConnection connection, long timeout) throws InterruptedException { + while (true) { + Object o = connection.getDispatchQueue().poll(timeout, TimeUnit.MILLISECONDS); + + if (o == null) { + return null; + } + if (o instanceof MessageDispatch) { + + MessageDispatch dispatch = (MessageDispatch)o; + if (dispatch.getMessage() == null) { + return null; + } + dispatch.setMessage(dispatch.getMessage().copy()); + dispatch.getMessage().setRedeliveryCounter(dispatch.getRedeliveryCounter()); + return dispatch.getMessage(); + } + } + }; + + protected void assertNoMessagesLeft(StubConnection connection) throws InterruptedException { + long wait = FAST_NO_MESSAGE_LEFT_ASSERT ? 0 : maxWait; + while (true) { + Object o = connection.getDispatchQueue().poll(wait, TimeUnit.MILLISECONDS); + if (o == null) { + return; + } + if (o instanceof MessageDispatch && ((MessageDispatch)o).getMessage() != null) { + fail("Received a message: "+((MessageDispatch)o).getMessage().getMessageId()); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ConcurrentConnectSimulationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ConcurrentConnectSimulationTest.java new file mode 100644 index 0000000000..0c791fdda0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ConcurrentConnectSimulationTest.java @@ -0,0 +1,59 @@ +/** + * 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.broker; + +import junit.framework.Test; + +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.SessionId; + +public class ConcurrentConnectSimulationTest extends BrokerTestSupport { + + /* + * simulate failover and retry of connection before broker has killed connection + * which appears as a concurrent connect request to the broker + * see: https://issues.apache.org/activemq/browse/AMQ-2241 + */ + public void testConcurrentConnection() throws Exception { + + StubConnection connection1 = createConnection(); + StubConnection connection2 = createConnection(); + + // reuse same connection info + ConnectionInfo connectionInfo = createConnectionInfo(); + connection1.request(connectionInfo); + connection2.request(connectionInfo); + + // second one should win out, verify using consumer on default session (watchAdvisories) + ConsumerId consumerId = new ConsumerId(new SessionId(connectionInfo.getConnectionId(), -1), 1); + ConsumerInfo consumerInfo = new ConsumerInfo(consumerId); + consumerInfo.setDestination(AdvisorySupport.TEMP_DESTINATION_COMPOSITE_ADVISORY_TOPIC); + + connection2.request(consumerInfo); + } + + public static Test suite() { + return suite(ConcurrentConnectSimulationTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/CreateDestinationsOnStartupViaXBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/CreateDestinationsOnStartupViaXBeanTest.java new file mode 100644 index 0000000000..70fda7c7f4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/CreateDestinationsOnStartupViaXBeanTest.java @@ -0,0 +1,69 @@ +/** + * 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.broker; + +import java.net.URI; +import java.util.Set; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.xbean.XBeanBrokerFactory; + +/** + * + * + */ +public class CreateDestinationsOnStartupViaXBeanTest extends EmbeddedBrokerTestSupport { + + public void testNewDestinationsAreCreatedOnStartup() throws Exception { + assertQueueCreated("FOO.BAR", true); + assertQueueCreated("FOO.DoesNotExist", false); + + assertTopicCreated("SOME.TOPIC", true); + assertTopicCreated("FOO.DoesNotExist", false); + } + + protected void assertQueueCreated(String name, boolean expected) throws Exception { + assertDestinationCreated(new ActiveMQQueue(name), expected); + } + + protected void assertTopicCreated(String name, boolean expected) throws Exception { + assertDestinationCreated(new ActiveMQTopic(name), expected); + } + + protected void assertDestinationCreated(ActiveMQDestination destination, boolean expected) throws Exception { + Set answer = broker.getBroker().getDestinations(destination); + int size = expected ? 1 : 0; + assertEquals("Could not find destination: " + destination + ". Size of found destinations: " + answer, size, answer.size()); + } + + protected BrokerService createBroker() throws Exception { + XBeanBrokerFactory factory = new XBeanBrokerFactory(); + BrokerService answer = factory.createBroker(new URI(getBrokerConfigUri())); + + // lets disable persistence as we are a test + answer.setPersistent(false); + + return answer; + } + + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/destinations-on-start.xml"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DedicatedTaskRunnerBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DedicatedTaskRunnerBrokerTest.java new file mode 100644 index 0000000000..c1864207c4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DedicatedTaskRunnerBrokerTest.java @@ -0,0 +1,37 @@ +/** + * 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.broker; + +import junit.framework.Test; + +public class DedicatedTaskRunnerBrokerTest extends BrokerTest { + + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.setDedicatedTaskRunner(true); + return broker; + } + + public static Test suite() { + return suite(DedicatedTaskRunnerBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DoubleSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DoubleSubscriptionTest.java new file mode 100644 index 0000000000..8fd129256e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DoubleSubscriptionTest.java @@ -0,0 +1,118 @@ +/** + * 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.broker; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.network.NetworkTestSupport; + +/** + * Pretend to be an abusive client that sends multiple identical ConsumerInfo + * commands and make sure the broker doesn't stall because of it. + */ + +public class DoubleSubscriptionTest extends NetworkTestSupport { + + public ActiveMQDestination destination; + public int deliveryMode; + + private String remoteURI = "tcp://localhost:0?wireFormat.tcpNoDelayEnabled=true"; + + public static Test suite() { + return suite(DoubleSubscriptionTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void initCombosForTestDoubleSubscription() { + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQQueue("TEST")}); + } + + public void testDoubleSubscription() throws Exception { + + // Start a normal consumer on the remote broker + StubConnection connection1 = createRemoteConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.request(consumerInfo1); + + // Start a normal producer on a remote broker + StubConnection connection2 = createRemoteConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(producerInfo2); + + // Send a message to make sure the basics are working + connection2.request(createMessage(producerInfo2, destination, DeliveryMode.PERSISTENT)); + + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNoMessagesLeft(connection1); + + connection1.send(createAck(consumerInfo1, m1, 1, MessageAck.STANDARD_ACK_TYPE)); + + // Send a message to sit on the broker while we mess with it + connection2.request(createMessage(producerInfo2, destination, DeliveryMode.PERSISTENT)); + + // Now we're going to resend the same consumer commands again and see if + // the broker + // can handle it. + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.request(consumerInfo1); + + // After this there should be 2 messages on the broker... + connection2.request(createMessage(producerInfo2, destination, DeliveryMode.PERSISTENT)); + + // ... let's start a fresh consumer... + connection1.stop(); + StubConnection connection3 = createRemoteConnection(); + ConnectionInfo connectionInfo3 = createConnectionInfo(); + SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); + ConsumerInfo consumerInfo3 = createConsumerInfo(sessionInfo3, destination); + connection3.send(connectionInfo3); + connection3.send(sessionInfo3); + connection3.request(consumerInfo3); + + // ... and then grab the 2 that should be there. + assertNotNull(receiveMessage(connection3)); + assertNotNull(receiveMessage(connection3)); + assertNoMessagesLeft(connection3); + } + + protected String getRemoteURI() { + return remoteURI; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DurablePersistentFalseRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DurablePersistentFalseRestartTest.java new file mode 100644 index 0000000000..b9724984e6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/DurablePersistentFalseRestartTest.java @@ -0,0 +1,90 @@ +/** + * 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.broker; + +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.transport.failover.FailoverTransport; + +public class DurablePersistentFalseRestartTest extends BrokerRestartTestSupport { + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + super.configureBroker(broker); + broker.setPersistent(false); + broker.setPersistenceAdapter(new KahaDBPersistenceAdapter()); + broker.addConnector("tcp://0.0.0.0:0"); + } + + public void testValidateNoPersistenceForDurableAfterRestart() throws Exception { + + ConnectionFactory connectionFactory = + new ActiveMQConnectionFactory("failover:(" + broker.getTransportConnectors().get(0).getPublishableConnectString() + ")"); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.setClientID("clientId"); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Topic destination = session.createTopic(queueName); + MessageConsumer consumer = session.createDurableSubscriber(destination, "subscriberName"); + + populateDestination(10, destination, connection); + + restartBroker(); + + // make failover aware of the restarted auto assigned port + ((FailoverTransport) connection.getTransport().narrow(FailoverTransport.class)).add(true, broker.getTransportConnectors().get(0).getPublishableConnectString()); + + TextMessage msg = (TextMessage) consumer.receive(4000); + assertNull("did not get a message when persistent=false, message: " + msg, msg); + + connection.close(); + } + + private void populateDestination(final int nbMessages, + final Destination destination, javax.jms.Connection connection) + throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + for (int i = 1; i <= nbMessages; i++) { + producer.send(session.createTextMessage("")); + } + producer.close(); + session.close(); + } + + + public static Test suite() { + return suite(DurablePersistentFalseRestartTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/JdbcXARecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/JdbcXARecoveryBrokerTest.java new file mode 100644 index 0000000000..5788dadf11 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/JdbcXARecoveryBrokerTest.java @@ -0,0 +1,89 @@ +/** + * 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.broker; + +import junit.framework.Test; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.apache.derby.jdbc.EmbeddedXADataSource; + +public class JdbcXARecoveryBrokerTest extends XARecoveryBrokerTest { + + EmbeddedXADataSource dataSource; + + @Override + protected void setUp() throws Exception { + dataSource = new EmbeddedXADataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + stopDerby(); + } + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + super.configureBroker(broker); + + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + jdbc.setDataSource(dataSource); + broker.setPersistenceAdapter(jdbc); + } + + @Override + protected void restartBroker() throws Exception { + broker.stop(); + stopDerby(); + dataSource = new EmbeddedXADataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + + broker = createRestartedBroker(); + broker.start(); + } + + private void stopDerby() { + LOG.info("STOPPING DB!@!!!!"); + final EmbeddedDataSource ds = dataSource; + try { + ds.setShutdownDatabase("shutdown"); + ds.getConnection(); + } catch (Exception ignored) { + } + + } + + public static Test suite() { + return suite(JdbcXARecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + protected ActiveMQDestination createDestination() { + return new ActiveMQQueue("test,special"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/Main.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/Main.java new file mode 100644 index 0000000000..9e1fa5e878 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/Main.java @@ -0,0 +1,86 @@ +/** + * 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.broker; + +import javax.jms.Connection; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.demo.DefaultQueueSender; + +/** + * A helper class which can be handy for running a broker in your IDE from the + * activemq-core module. + * + * + */ +public final class Main { + protected static boolean createConsumers; + + private Main() { + } + + /** + * @param args + */ + public static void main(String[] args) { + try { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + + // String brokerDir = "xbean:...; + // System.setProperty("activemq.base", brokerDir); + // BrokerService broker = BrokerFactory.createBroker(new URI(brokerDir + "/activemq.xml")); + + // for running on Java 5 without mx4j + ManagementContext managementContext = broker.getManagementContext(); + managementContext.setFindTigerMbeanServer(true); + managementContext.setUseMBeanServer(true); + managementContext.setCreateConnector(false); + + broker.setUseJmx(true); + // broker.setPlugins(new BrokerPlugin[] { new + // ConnectionDotFilePlugin(), new UDPTraceBrokerPlugin() }); + broker.addConnector("tcp://localhost:61616"); + broker.addConnector("stomp://localhost:61613"); + broker.start(); + + // lets publish some messages so that there is some stuff to browse + DefaultQueueSender.main(new String[] {"Prices.Equity.IBM"}); + DefaultQueueSender.main(new String[] {"Prices.Equity.MSFT"}); + + // lets create a dummy couple of consumers + if (createConsumers) { + Connection connection = new ActiveMQConnectionFactory().createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createConsumer(new ActiveMQQueue("Orders.IBM")); + session.createConsumer(new ActiveMQQueue("Orders.MSFT"), "price > 100"); + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session2.createConsumer(new ActiveMQQueue("Orders.MSFT"), "price > 200"); + } else { + // Lets wait for the broker + broker.waitUntilStopped(); + } + } catch (Exception e) { + System.out.println("Failed: " + e); + e.printStackTrace(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/MarshallingBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/MarshallingBrokerTest.java new file mode 100644 index 0000000000..31751562ff --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/MarshallingBrokerTest.java @@ -0,0 +1,75 @@ +/** + * 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.broker; + +import java.io.IOException; + +import junit.framework.Test; + +import org.apache.activemq.command.Command; +import org.apache.activemq.command.Response; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.wireformat.WireFormat; + +/** + * Runs against the broker but marshals all request and response commands. + * + * + */ +public class MarshallingBrokerTest extends BrokerTest { + + public WireFormat wireFormat = new OpenWireFormat(); + + public void initCombos() { + + OpenWireFormat wf1 = new OpenWireFormat(); + wf1.setCacheEnabled(false); + OpenWireFormat wf2 = new OpenWireFormat(); + wf2.setCacheEnabled(true); + + addCombinationValues("wireFormat", new Object[] {wf1, wf2, }); + } + + protected StubConnection createConnection() throws Exception { + return new StubConnection(broker) { + public Response request(Command command) throws Exception { + Response r = super.request((Command)wireFormat.unmarshal(wireFormat.marshal(command))); + if (r != null) { + r = (Response)wireFormat.unmarshal(wireFormat.marshal(r)); + } + return r; + } + + public void send(Command command) throws Exception { + super.send((Command)wireFormat.unmarshal(wireFormat.marshal(command))); + } + + protected void dispatch(Command command) throws InterruptedException, IOException { + super.dispatch((Command)wireFormat.unmarshal(wireFormat.marshal(command))); + }; + }; + } + + public static Test suite() { + return suite(MarshallingBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/MessageExpirationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/MessageExpirationTest.java new file mode 100644 index 0000000000..5c7f29d257 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/MessageExpirationTest.java @@ -0,0 +1,274 @@ +/** + * 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.broker; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; + +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.VMPendingSubscriberMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.LocalTransactionId; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; + +public class MessageExpirationTest extends BrokerTestSupport { + + public ActiveMQDestination destination; + public int deliveryMode = DeliveryMode.NON_PERSISTENT; + public int prefetch; + public byte destinationType = ActiveMQDestination.QUEUE_TYPE; + public boolean durableConsumer; + + protected Message createMessage(ProducerInfo producerInfo, ActiveMQDestination destination, int deliveryMode, int timeToLive) { + Message message = createMessage(producerInfo, destination, deliveryMode); + long now = System.currentTimeMillis(); + message.setTimestamp(now); + message.setExpiration(now + timeToLive); + return message; + } + + public void initCombosForTestMessagesWaitingForUssageDecreaseExpire() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + return broker; + } + + protected PolicyEntry getDefaultPolicy() { + PolicyEntry policy = super.getDefaultPolicy(); + // disable spooling + policy.setPendingSubscriberPolicy(new VMPendingSubscriberMessageStoragePolicy()); + // have aggressive expiry period to ensure no deadlock or clash + policy.setExpireMessagesPeriod(100); + + return policy; + } + + public void testMessagesWaitingForUsageDecreaseExpire() throws Exception { + + // Start a producer + final StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + final ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // Start a consumer.. + final StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + + destination = createDestinationInfo(connection2, connectionInfo2, destinationType); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(1); + connection2.request(consumerInfo2); + + // Reduce the limit so that only 1 message can flow through the broker + // at a time. + broker.getSystemUsage().getMemoryUsage().setLimit(1); + + final Message m1 = createMessage(producerInfo, destination, deliveryMode); + final Message m2 = createMessage(producerInfo, destination, deliveryMode, 1000); + final Message m3 = createMessage(producerInfo, destination, deliveryMode); + final Message m4 = createMessage(producerInfo, destination, deliveryMode, 1000); + + // Produce in an async thread since the producer will be getting blocked + // by the usage manager.. + new Thread() { + public void run() { + // m1 and m3 should not expire.. but the others should. + try { + connection.send(m1); + connection.send(m2); + connection.send(m3); + connection.send(m4); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start(); + + // Make sure only 1 message was delivered due to prefetch == 1 + Message m = receiveMessage(connection2); + assertNotNull(m); + assertEquals(m1.getMessageId(), m.getMessageId()); + assertNoMessagesLeft(connection); + + // Sleep before we ack so that the messages expire on the usage manager + Thread.sleep(1500); + connection2.send(createAck(consumerInfo2, m, 1, MessageAck.STANDARD_ACK_TYPE)); + + // 2nd message received should be m3.. it should have expired 2nd + // message sent. + m = receiveMessage(connection2); + assertNotNull(m); + assertEquals(m3.getMessageId(), m.getMessageId()); + + // Sleep before we ack so that the messages expire on the usage manager + Thread.sleep(1500); + connection2.send(createAck(consumerInfo2, m, 1, MessageAck.STANDARD_ACK_TYPE)); + + // And there should be no messages left now.. + assertNoMessagesLeft(connection2); + + connection.send(closeConnectionInfo(connectionInfo)); + connection.send(closeConnectionInfo(connectionInfo2)); + } + + public void initCombosForTestMessagesInLongTransactionExpire() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.PERSISTENT), Integer.valueOf(DeliveryMode.NON_PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testMessagesInLongTransactionExpire() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1000); + connection.send(consumerInfo); + + // Start the tx.. + LocalTransactionId txid = createLocalTransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + // m1 and m3 should not expire.. but the others should. + Message m1 = createMessage(producerInfo, destination, deliveryMode); + m1.setTransactionId(txid); + connection.send(m1); + Message m = createMessage(producerInfo, destination, deliveryMode, 1000); + m.setTransactionId(txid); + connection.send(m); + Message m3 = createMessage(producerInfo, destination, deliveryMode); + m3.setTransactionId(txid); + connection.send(m3); + m = createMessage(producerInfo, destination, deliveryMode, 1000); + m.setTransactionId(txid); + connection.send(m); + + // Sleep before we commit so that the messages expire on the commit + // list.. + Thread.sleep(1500); + connection.send(createCommitTransaction1Phase(connectionInfo, txid)); + + m = receiveMessage(connection); + assertNotNull(m); + assertEquals(m1.getMessageId(), m.getMessageId()); + connection.send(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + + // 2nd message received should be m3.. it should have expired 2nd + // message sent. + m = receiveMessage(connection); + assertNotNull(m); + assertEquals(m3.getMessageId(), m.getMessageId()); + connection.send(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + + // And there should be no messages left now.. + assertNoMessagesLeft(connection); + + connection.send(closeConnectionInfo(connectionInfo)); + } + + public void initCombosForTestMessagesInSubscriptionPendingListExpire() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TOPIC_TYPE), + Byte.valueOf(ActiveMQDestination.TEMP_QUEUE_TYPE), Byte.valueOf(ActiveMQDestination.TEMP_TOPIC_TYPE)}); + } + + public void testMessagesInSubscriptionPendingListExpire() throws Exception { + + // Start a producer and consumer + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + destination = createDestinationInfo(connection, connectionInfo, destinationType); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1); + connection.send(consumerInfo); + + // m1 and m3 should not expire.. but the others should. + Message m1 = createMessage(producerInfo, destination, deliveryMode); + connection.send(m1); + connection.send(createMessage(producerInfo, destination, deliveryMode, 1000)); + Message m3 = createMessage(producerInfo, destination, deliveryMode); + connection.send(m3); + connection.send(createMessage(producerInfo, destination, deliveryMode, 1000)); + + // Make sure only 1 message was delivered due to prefetch == 1 + Message m = receiveMessage(connection); + assertNotNull(m); + assertEquals(m1.getMessageId(), m.getMessageId()); + assertNoMessagesLeft(connection); + + // Sleep before we ack so that the messages expire on the pending list.. + Thread.sleep(1500); + connection.send(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + + // 2nd message received should be m3.. it should have expired 2nd + // message sent. + m = receiveMessage(connection); + assertNotNull(m); + assertEquals(m3.getMessageId(), m.getMessageId()); + connection.send(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + + // And there should be no messages left now.. + assertNoMessagesLeft(connection); + + connection.send(closeConnectionInfo(connectionInfo)); + } + + public static Test suite() { + return suite(MessageExpirationTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/NioQueueSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/NioQueueSubscriptionTest.java new file mode 100644 index 0000000000..898256ce7d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/NioQueueSubscriptionTest.java @@ -0,0 +1,134 @@ +/** + * 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.broker; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.ConnectionFactory; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +@RunWith(BlockJUnit4ClassRunner.class) +public class NioQueueSubscriptionTest extends QueueSubscriptionTest { + + protected static final Logger LOG = LoggerFactory.getLogger(NioQueueSubscriptionTest.class); + + private final Map exceptions = Collections.synchronizedMap(new HashMap()); + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("tcp://localhost:62621?trace=false"); + } + + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = BrokerFactory.createBroker(new URI( + "broker://nio://localhost:62621?useQueueForAccept=false&persistent=false&wiewformat.maxInactivityDuration=0")); + answer.getManagementContext().setCreateConnector(false); + answer.setUseJmx(false); + answer.setDeleteAllMessagesOnStartup(true); + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setQueue(">"); + entry.setOptimizedDispatch(true); + policyEntries.add(entry); + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + answer.setDestinationPolicy(policyMap); + return answer; + } + + + @Ignore("See AMQ-4286") + @Test(timeout = 60 * 1000) + public void testLotsOfConcurrentConnections() throws Exception { + ExecutorService executor = Executors.newCachedThreadPool(); + final ConnectionFactory factory = createConnectionFactory(); + int connectionCount = 400; + final AtomicInteger threadId = new AtomicInteger(0); + for (int i = 0; i < connectionCount; i++) { + executor.execute(new Runnable() { + @Override + public void run() { + final int innerId = threadId.incrementAndGet(); + try { + ExceptionListener listener = new NioQueueSubscriptionTestListener(innerId, exceptions, LOG); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.setExceptionListener(listener); + connection.start(); + assertNotNull(connection.getBrokerName()); + connections.add(connection); + } catch (Exception e) { + LOG.error(">>>> Exception in run() on thread " + innerId, e); + exceptions.put(Thread.currentThread(), e); + } + } + }); + } + + executor.shutdown(); + executor.awaitTermination(30, TimeUnit.SECONDS); + + if (!exceptions.isEmpty()) { + LOG.error(">>>> " + exceptions.size() + " exceptions like", exceptions.values().iterator().next()); + fail("unexpected exceptions in worker threads: " + exceptions.values().iterator().next()); + } + LOG.info("created " + connectionCount + " connections"); + } +} + +class NioQueueSubscriptionTestListener implements ExceptionListener { + private int id = 0; + protected Logger LOG; + private final Map exceptions; + + public NioQueueSubscriptionTestListener(int id, Map exceptions, Logger log) { + this.id = id; + this.exceptions = exceptions; + this.LOG = log; + } + + @Override + public void onException(JMSException exception) { + LOG.error(">>>> Exception in onException() on thread " + id, exception); + exceptions.put(Thread.currentThread(), exception); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/OutOfOrderXMLTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/OutOfOrderXMLTest.java new file mode 100644 index 0000000000..11fbb56902 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/OutOfOrderXMLTest.java @@ -0,0 +1,33 @@ +/** + * 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.broker; + +import java.net.URI; +import org.apache.activemq.xbean.XBeanBrokerFactory; +import org.junit.Test; + +// https://issues.apache.org/activemq/browse/AMQ-2939 +public class OutOfOrderXMLTest { + + @Test + public void verifyBrokerCreationWhenXmlOutOfOrderValidationFalse() throws Exception { + BrokerService answer = + BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/broker/out-of-order-broker-elements.xml?validate=false")); + answer.stop(); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ProgressPrinter.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ProgressPrinter.java new file mode 100644 index 0000000000..dcf4b6e614 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ProgressPrinter.java @@ -0,0 +1,43 @@ +/** + * 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.broker; + +public class ProgressPrinter { + + private final long total; + private final long interval; + private long percentDone; + private long counter; + + public ProgressPrinter(long total, long interval) { + this.total = total; + this.interval = interval; + } + + public synchronized void increment() { + update(++counter); + } + + public synchronized void update(long current) { + long at = 100 * current / total; + if ((percentDone / interval) != (at / interval)) { + percentDone = at; + System.out.println("Completed: " + percentDone + "%"); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/QueueMbeanRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/QueueMbeanRestartTest.java new file mode 100644 index 0000000000..c004fefca2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/QueueMbeanRestartTest.java @@ -0,0 +1,123 @@ +/** + * 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.broker; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; + +import org.apache.activemq.TestSupport; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.JMXSupport; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class QueueMbeanRestartTest extends TestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(QueueMbeanRestartTest.class); + + BrokerService broker; + + private final TestSupport.PersistenceAdapterChoice persistenceAdapterChoice; + + @Parameterized.Parameters + public static Collection getTestParameters() { + TestSupport.PersistenceAdapterChoice[] kahaDb = {TestSupport.PersistenceAdapterChoice.KahaDB}; + TestSupport.PersistenceAdapterChoice[] levelDb = {TestSupport.PersistenceAdapterChoice.LevelDB}; + TestSupport.PersistenceAdapterChoice[] jdbc = {TestSupport.PersistenceAdapterChoice.JDBC}; + List choices = new ArrayList(); + choices.add(kahaDb); + choices.add(levelDb); + choices.add(jdbc); + + return choices; + } + + public QueueMbeanRestartTest(TestSupport.PersistenceAdapterChoice choice) { + this.persistenceAdapterChoice = choice; + } + + @Before + public void setUp() throws Exception { + topic = false; + super.setUp(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + broker.stop(); + } + + @Test(timeout = 60000) + public void testMBeanPresenceOnRestart() throws Exception { + createBroker(true); + + sendMessages(); + verifyPresenceOfQueueMbean(); + LOG.info("restart...."); + + restartBroker(); + verifyPresenceOfQueueMbean(); + } + + private void restartBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + Thread.sleep(5 * 1000); + createBroker(false); + broker.waitUntilStarted(); + } + + private void verifyPresenceOfQueueMbean() throws Exception { + for (ObjectName name : broker.getManagementContext().queryNames(null, null)) { + LOG.info("candidate :" + name); + String type = name.getKeyProperty("destinationType"); + if (type != null && type.equals("Queue")) { + assertEquals( + JMXSupport.encodeObjectNamePart(((ActiveMQQueue) createDestination()).getPhysicalName()), + name.getKeyProperty("destinationName")); + LOG.info("found mbbean " + name); + return; + } + } + fail("expected to find matching queue mbean for: " + createDestination()); + } + + private void sendMessages() throws Exception { + Session session = createConnection().createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(createDestination()); + producer.send(session.createTextMessage()); + } + + private void createBroker(boolean deleteAll) throws Exception { + broker = new BrokerService(); + setPersistenceAdapter(broker, persistenceAdapterChoice); + + broker.setDeleteAllMessagesOnStartup(deleteAll); + broker.start(); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/QueueSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/QueueSubscriptionTest.java new file mode 100644 index 0000000000..6c3dc159cb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/QueueSubscriptionTest.java @@ -0,0 +1,188 @@ +/** + * 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.broker; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleClientsTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +@RunWith(BlockJUnit4ClassRunner.class) +public class QueueSubscriptionTest extends JmsMultipleClientsTestSupport { + protected int messageCount = 1000; // 1000 Messages per producer + protected int prefetchCount = 10; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + durable = false; + topic = false; + } + + @After + @Override + public void tearDown() throws Exception { + super.tearDown(); + } + + + @Test(timeout = 60 * 1000) + public void testManyProducersOneConsumer() throws Exception { + consumerCount = 1; + producerCount = 10; + messageCount = 100; + messageSize = 1; // 1 byte + prefetchCount = 10; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersSmallMessagesOnePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + messageCount = 1000; + messageSize = 1024; // 1 Kb + configurePrefetchOfOne(); + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersSmallMessagesLargePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + messageCount = 1000; + prefetchCount = messageCount * 2; + messageSize = 1024; // 1 Kb + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 2 * 60 * 1000) + public void testOneProducerTwoConsumersLargeMessagesOnePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + messageCount = 10; + messageSize = 1024 * 1024 * 1; // 2 MB + configurePrefetchOfOne(); + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersLargeMessagesLargePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + messageCount = 10; + prefetchCount = messageCount * 2; + messageSize = 1024 * 1024 * 1; // 2 MB + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerManyConsumersFewMessages() throws Exception { + consumerCount = 50; + producerCount = 1; + messageCount = 10; + messageSize = 1; // 1 byte + prefetchCount = 10; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerManyConsumersManyMessages() throws Exception { + consumerCount = 50; + producerCount = 1; + messageCount = 1000; + messageSize = 1; // 1 byte + prefetchCount = messageCount / consumerCount; + allMessagesList.setMaximumDuration(allMessagesList.getMaximumDuration() * 20); + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 2 * 60 * 1000) + public void testManyProducersManyConsumers() throws Exception { + consumerCount = 200; + producerCount = 50; + messageCount = 100; + messageSize = 1; // 1 byte + prefetchCount = 100; + allMessagesList.setMaximumDuration(allMessagesList.getMaximumDuration() * 20); + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + protected void configurePrefetchOfOne() { + prefetchCount = 1; + + // this is gonna be a bit slow what with the low prefetch so bump up the + // wait time + allMessagesList.setMaximumDuration(allMessagesList.getMaximumDuration() * 20); + } + + public void doMultipleClientsTest() throws Exception { + // Create destination + final ActiveMQDestination dest = createDestination(); + + // Create consumers + ActiveMQConnectionFactory consumerFactory = (ActiveMQConnectionFactory)createConnectionFactory(); + consumerFactory.getPrefetchPolicy().setAll(prefetchCount); + + startConsumers(consumerFactory, dest); + + startProducers(dest, messageCount); + + // Wait for messages to be received. Make it proportional to the + // messages delivered. + int totalMessageCount = messageCount * producerCount; + if (dest.isTopic()) { + totalMessageCount *= consumerCount; + } + waitForAllMessagesToBeReceived(totalMessageCount); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ReconnectWithJMXEnabledTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ReconnectWithJMXEnabledTest.java new file mode 100644 index 0000000000..181a90777c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ReconnectWithJMXEnabledTest.java @@ -0,0 +1,92 @@ +/** + * 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.broker; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; + +/** + * + * + */ +public class ReconnectWithJMXEnabledTest extends EmbeddedBrokerTestSupport { + + protected Connection connection; + protected boolean transacted; + protected int authMode = Session.AUTO_ACKNOWLEDGE; + + public void testTestUseConnectionCloseBrokerThenRestartInSameJVM() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + connection.close(); + + broker.stop(); + broker = createBroker(); + startBroker(); + + connectionFactory = createConnectionFactory(); + connection = connectionFactory.createConnection(); + useConnection(connection); + } + + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + super.setUp(); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString()); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseJmx(true); + answer.setPersistent(isPersistent()); + answer.addConnector(bindAddress); + return answer; + } + + protected void useConnection(Connection connection) throws Exception { + connection.setClientID("foo"); + connection.start(); + Session session = connection.createSession(transacted, authMode); + Destination destination = createDestination(); + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(destination); + Message message = session.createTextMessage("Hello World"); + producer.send(message); + Thread.sleep(1000); + consumer.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RecoveryBrokerTest.java new file mode 100644 index 0000000000..491a585de4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RecoveryBrokerTest.java @@ -0,0 +1,586 @@ +/** + * 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.broker; + +import java.util.ArrayList; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.LocalTransactionId; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.command.XATransactionId; + +/** + * Used to simulate the recovery that occurs when a broker shuts down. + * + * + */ +public class RecoveryBrokerTest extends BrokerRestartTestSupport { + + /** + * Used to verify that after a broker restart durable subscriptions that use + * wild cards are still wild card subscription after broker restart. + * + * @throws Exception + */ + //need to revist!!! + public void XtestWildCardSubscriptionPreservedOnRestart() throws Exception { + ActiveMQDestination dest1 = new ActiveMQTopic("TEST.A"); + ActiveMQDestination dest2 = new ActiveMQTopic("TEST.B"); + ActiveMQDestination dest3 = new ActiveMQTopic("TEST.C"); + ActiveMQDestination wildDest = new ActiveMQTopic("TEST.>"); + + ArrayList sentBeforeRestart = new ArrayList(); + ArrayList sentBeforeCreateConsumer = new ArrayList(); + ArrayList sentAfterCreateConsumer = new ArrayList(); + + // Setup a first connection + { + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + connectionInfo1.setClientId("A"); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + // Create the durable subscription. + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, wildDest); + consumerInfo1.setSubscriptionName("test"); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Close the subscription. + connection1.send(closeConsumerInfo(consumerInfo1)); + + // Send the messages + for (int i = 0; i < 4; i++) { + Message m = createMessage(producerInfo1, dest1, DeliveryMode.PERSISTENT); + connection1.send(m); + sentBeforeRestart.add(m.getMessageId()); + } + connection1.request(closeConnectionInfo(connectionInfo1)); + connection1.stop(); + } + + // Restart the broker. + restartBroker(); + + // Get a connection to the new broker. + { + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + connectionInfo2.setClientId("A"); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + connection2.send(producerInfo2); + + // Send messages before the durable subscription is re-activated. + for (int i = 0; i < 4; i++) { + Message m = createMessage(producerInfo2, dest2, DeliveryMode.PERSISTENT); + connection2.send(m); + sentBeforeCreateConsumer.add(m.getMessageId()); + } + + // Re-open the subscription. + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, wildDest); + consumerInfo2.setSubscriptionName("test"); + consumerInfo2.setPrefetchSize(100); + connection2.send(consumerInfo2); + + // Send messages after the subscription is activated. + for (int i = 0; i < 4; i++) { + Message m = createMessage(producerInfo2, dest3, DeliveryMode.PERSISTENT); + connection2.send(m); + sentAfterCreateConsumer.add(m.getMessageId()); + } + + // We should get the recovered messages... + for (int i = 0; i < 4; i++) { + Message m2 = receiveMessage(connection2); + assertNotNull("Recovered message missing: " + i, m2); + assertEquals(sentBeforeRestart.get(i), m2.getMessageId()); + } + + // We should get get the messages that were sent before the sub was + // reactivated. + for (int i = 0; i < 4; i++) { + Message m2 = receiveMessage(connection2); + assertNotNull("Before activated message missing: " + i, m2); + assertEquals(sentBeforeCreateConsumer.get(i), m2.getMessageId()); + } + + // We should get get the messages that were sent after the sub was + // reactivated. + for (int i = 0; i < 4; i++) { + Message m2 = receiveMessage(connection2); + assertNotNull("After activated message missing: " + i, m2); + assertEquals("" + i, sentAfterCreateConsumer.get(i), m2.getMessageId()); + } + + assertNoMessagesLeft(connection2); + } + + } + + public void testConsumedQueuePersistentMessagesLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // The we should get the messages. + for (int i = 0; i < 4; i++) { + Message m2 = receiveMessage(connection); + assertNotNull(m2); + } + + // restart the broker. + restartBroker(); + + // No messages should be delivered. + Message m = receiveMessage(connection); + assertNull(m); + } + + public void testQueuePersistentUncommitedMessagesLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // Begin the transaction. + LocalTransactionId txid = createLocalTransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + } + + // Don't commit + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // No messages should be delivered. + Message m = receiveMessage(connection); + assertNull(m); + } + + public void testTopicDurableConsumerHoldsPersistentMessageAfterRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TEST"); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + connectionInfo1.setClientId("A"); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo1 = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo1); + + // Create the durable subscription. + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setSubscriptionName("test"); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Close the subscription. + connection1.send(closeConsumerInfo(consumerInfo1)); + + // Send the messages + connection1.send(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + connection1.send(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + connection1.send(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + connection1.send(createMessage(producerInfo1, destination, DeliveryMode.PERSISTENT)); + connection1.request(closeConnectionInfo(connectionInfo1)); + // Restart the broker. + restartBroker(); + + // Get a connection to the new broker. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + connectionInfo2.setClientId("A"); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + + // Re-open the subscription. + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setSubscriptionName("test"); + consumerInfo2.setPrefetchSize(100); + connection2.send(consumerInfo2); + + // The we should get the messages. + for (int i = 0; i < 4; i++) { + Message m2 = receiveMessage(connection2); + assertNotNull("Did not get message "+i, m2); + } + assertNoMessagesLeft(connection2); + } + + public void testQueuePersistentMessagesNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + connection.request(closeConnectionInfo(connectionInfo)); + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Message should have been dropped due to broker restart. + Message m = receiveMessage(connection); + assertNotNull("Should have received a message by now!", m); + assertEquals(m.getMessageId(), message.getMessageId()); + } + + public void testQueueNonPersistentMessagesLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + Message message = createMessage(producerInfo, destination); + message.setPersistent(false); + connection.send(message); + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Message should have been dropped due to broker restart. + assertNoMessagesLeft(connection); + } + + public void testQueuePersistentCommitedMessagesNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // Begin the transaction. + LocalTransactionId txid = createLocalTransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + } + + // Commit + connection.send(createCommitTransaction1Phase(connectionInfo, txid)); + connection.request(closeConnectionInfo(connectionInfo)); + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + for (int i = 0; i < 4; i++) { + Message m = receiveMessage(connection); + assertNotNull(m); + } + + assertNoMessagesLeft(connection); + } + + + public void testQueuePersistentCommitedAcksNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Setup the consumer and receive the message. + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Begin the transaction. + LocalTransactionId txid = createLocalTransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + for (int i = 0; i < 4; i++) { + Message m = receiveMessage(connection); + assertNotNull(m); + MessageAck ack = createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + // Commit + connection.send(createCommitTransaction1Phase(connectionInfo, txid)); + connection.request(closeConnectionInfo(connectionInfo)); + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // No messages should be delivered. + Message m = receiveMessage(connection); + assertNull(m); + } + + + + public void testQueuePersistentUncommitedAcksLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Setup the consumer and receive the message. + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Begin the transaction. + LocalTransactionId txid = createLocalTransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + for (int i = 0; i < 4; i++) { + Message m = receiveMessage(connection); + assertNotNull(m); + MessageAck ack = createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + // Don't commit + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // All messages should be re-delivered. + for (int i = 0; i < 4; i++) { + Message m = receiveMessage(connection); + assertNotNull(m); + } + + assertNoMessagesLeft(connection); + } + + public void testQueuePersistentXAUncommitedAcksLostOnRestart() throws Exception { + int NUMBER = 100; + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < NUMBER; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Setup the consumer and receive the message. + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + Message m = null; + for (int i = 0; i < NUMBER; i++) { + m = receiveMessage(connection); + assertNotNull(m); + } + MessageAck ack = createAck(consumerInfo, m, NUMBER, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + + // Don't commit + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // All messages should be re-delivered. + for (int i = 0; i < NUMBER; i++) { + m = receiveMessage(connection); + assertNotNull(m); + } + + assertNoMessagesLeft(connection); + } + + public static Test suite() { + return suite(RecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RedeliveryRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RedeliveryRestartTest.java new file mode 100644 index 0000000000..032934b112 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RedeliveryRestartTest.java @@ -0,0 +1,297 @@ +/** + * 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.broker; + +import java.util.Arrays; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TopicSubscriber; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.transport.failover.FailoverTransport; +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class RedeliveryRestartTest extends TestSupport { + + private static final transient Logger LOG = LoggerFactory.getLogger(RedeliveryRestartTest.class); + ActiveMQConnection connection; + BrokerService broker = null; + String queueName = "redeliveryRestartQ"; + + @Parameterized.Parameter + public TestSupport.PersistenceAdapterChoice persistenceAdapterChoice = PersistenceAdapterChoice.KahaDB; + + @Parameterized.Parameters(name="Store={0}") + public static Iterable data() { + return Arrays.asList(new Object[][]{{TestSupport.PersistenceAdapterChoice.KahaDB},{TestSupport.PersistenceAdapterChoice.JDBC},{TestSupport.PersistenceAdapterChoice.LevelDB}}); + } + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + configureBroker(broker); + broker.setDeleteAllMessagesOnStartup(true); + broker.start(); + } + + @Override + @After + public void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + broker.stop(); + super.tearDown(); + } + + protected void configureBroker(BrokerService broker) throws Exception { + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setPersistJMSRedelivered(true); + policyMap.setDefaultEntry(policy); + broker.setDestinationPolicy(policyMap); + setPersistenceAdapter(broker, persistenceAdapterChoice); + broker.addConnector("tcp://0.0.0.0:0"); + } + + @org.junit.Test + public void testValidateRedeliveryFlagAfterRestartNoTx() throws Exception { + + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(" + broker.getTransportConnectors().get(0).getPublishableConnectString() + + ")?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination destination = session.createQueue(queueName); + populateDestination(10, destination, connection); + + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = null; + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(20000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + } + consumer.close(); + + restartBroker(); + + // make failover aware of the restarted auto assigned port + connection.getTransport().narrow(FailoverTransport.class).add(true, broker.getTransportConnectors().get(0) + .getPublishableConnectString()); + + consumer = session.createConsumer(destination); + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("redelivered? got: " + msg); + assertNotNull("got the message again", msg); + assertEquals("re delivery flag", true, msg.getJMSRedelivered()); + assertEquals("redelivery count survives restart", 2, msg.getLongProperty("JMSXDeliveryCount")); + msg.acknowledge(); + } + + // consume the rest that were not redeliveries + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(20000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + msg.acknowledge(); + } + connection.close(); + } + + @org.junit.Test + public void testDurableSubRedeliveryFlagAfterRestartNotSupported() throws Exception { + + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(" + broker.getTransportConnectors().get(0).getPublishableConnectString() + + ")?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.setClientID("id"); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + ActiveMQTopic destination = new ActiveMQTopic(queueName); + + TopicSubscriber durableSub = session.createDurableSubscriber(destination, "id"); + + populateDestination(10, destination, connection); + + TextMessage msg = null; + for (int i = 0; i < 5; i++) { + msg = (TextMessage) durableSub.receive(20000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + } + durableSub.close(); + + restartBroker(); + + // make failover aware of the restarted auto assigned port + connection.getTransport().narrow(FailoverTransport.class).add(true, broker.getTransportConnectors().get(0) + .getPublishableConnectString()); + + durableSub = session.createDurableSubscriber(destination, "id"); + for (int i = 0; i < 10; i++) { + msg = (TextMessage) durableSub.receive(4000); + LOG.info("redelivered? got: " + msg); + assertNotNull("got the message again", msg); + assertEquals("no reDelivery flag", false, msg.getJMSRedelivered()); + msg.acknowledge(); + } + connection.close(); + } + + @org.junit.Test + public void testValidateRedeliveryFlagAfterRestart() throws Exception { + + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(" + broker.getTransportConnectors().get(0).getPublishableConnectString() + + ")?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(queueName); + populateDestination(10, destination, connection); + + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = null; + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(20000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + } + session.rollback(); + consumer.close(); + + restartBroker(); + + // make failover aware of the restarted auto assigned port + connection.getTransport().narrow(FailoverTransport.class).add(true, broker.getTransportConnectors().get(0) + .getPublishableConnectString()); + + consumer = session.createConsumer(destination); + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("redelivered? got: " + msg); + assertNotNull("got the message again", msg); + assertEquals("redelivery count survives restart", 2, msg.getLongProperty("JMSXDeliveryCount")); + assertEquals("re delivery flag", true, msg.getJMSRedelivered()); + } + session.commit(); + + // consume the rest that were not redeliveries + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(20000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + } + session.commit(); + + connection.close(); + } + + @org.junit.Test + public void testValidateRedeliveryFlagAfterRecovery() throws Exception { + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString() + + "?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(queueName); + populateDestination(1, destination, connection); + + MessageConsumer consumer = session.createConsumer(destination); + TextMessage msg = (TextMessage) consumer.receive(5000); + LOG.info("got: " + msg); + assertNotNull("got the message", msg); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + + stopBrokerWithStoreFailure(broker, persistenceAdapterChoice); + + broker = createRestartedBroker(); + broker.start(); + + connection.close(); + + connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString()); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + session = connection.createSession(true, Session.SESSION_TRANSACTED); + consumer = session.createConsumer(destination); + msg = (TextMessage) consumer.receive(10000); + assertNotNull("got the message again", msg); + assertEquals("redelivery count survives restart", 2, msg.getLongProperty("JMSXDeliveryCount")); + assertEquals("re delivery flag", true, msg.getJMSRedelivered()); + + session.commit(); + connection.close(); + } + + private void restartBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + broker = createRestartedBroker(); + broker.start(); + } + + private BrokerService createRestartedBroker() throws Exception { + broker = new BrokerService(); + configureBroker(broker); + return broker; + } + + private void populateDestination(final int nbMessages, final Destination destination, javax.jms.Connection connection) throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + for (int i = 1; i <= nbMessages; i++) { + producer.send(session.createTextMessage("")); + } + producer.close(); + session.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RedeliveryRestartWithExceptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RedeliveryRestartWithExceptionTest.java new file mode 100644 index 0000000000..5d8b62ec81 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/RedeliveryRestartWithExceptionTest.java @@ -0,0 +1,472 @@ +/** + * 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.broker; + +import java.io.File; +import java.io.IOException; +import java.util.Set; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.scheduler.JobSchedulerStore; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.store.MessageStore; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.ProxyMessageStore; +import org.apache.activemq.store.ProxyTopicMessageStore; +import org.apache.activemq.store.TopicMessageStore; +import org.apache.activemq.store.TransactionStore; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.transport.tcp.TcpTransport; +import org.apache.activemq.usage.SystemUsage; +import org.junit.After; +import org.junit.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RedeliveryRestartWithExceptionTest extends TestSupport { + + private static final transient Logger LOG = LoggerFactory.getLogger(RedeliveryRestartWithExceptionTest.class); + ActiveMQConnection connection; + BrokerService broker = null; + String queueName = "redeliveryRestartQ"; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + configureBroker(broker, true); + broker.setDeleteAllMessagesOnStartup(true); + broker.start(); + } + + @Override + @After + public void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + broker.stop(); + super.tearDown(); + } + + protected void configureBroker(BrokerService broker, boolean throwExceptionOnUpdate) throws Exception { + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setPersistJMSRedelivered(true); + policyMap.setDefaultEntry(policy); + broker.setDestinationPolicy(policyMap); + broker.setPersistenceAdapter(new KahaDBWithUpdateExceptionPersistenceAdapter(throwExceptionOnUpdate)); + broker.addConnector("tcp://0.0.0.0:0"); + } + + @org.junit.Test + public void testValidateRedeliveryFlagAfterRestart() throws Exception { + + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString() + + "?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination destination = session.createQueue(queueName); + populateDestination(10, destination, connection, true); + TextMessage msg = null; + MessageConsumer consumer = session.createConsumer(destination); + Exception expectedException = null; + try { + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(5000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertTrue("Should not receive the 5th message", i < 4); + //The first 4 messages will be ok but the 5th one should hit an exception in updateMessage and should not be delivered + } + } catch (Exception e) { + //Expecting an exception and disconnect on the 5th message + LOG.info("Got expected:", e); + expectedException = e; + } + assertNotNull("Expecting an exception when updateMessage fails", expectedException); + + consumer.close(); + connection.close(); + + restartBroker(); + + connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString() + + "?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = session.createQueue(queueName); + consumer = session.createConsumer(destination); + + + // consume the messages that were previously delivered + for (int i = 0; i < 4; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("redelivered? got: " + msg); + assertNotNull("got the message again", msg); + assertEquals("re delivery flag", true, msg.getJMSRedelivered()); + assertTrue("redelivery count survives restart", msg.getLongProperty("JMSXDeliveryCount") > 1); + msg.acknowledge(); + } + + + // consume the rest that were not redeliveries + for (int i = 0; i < 6; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + msg.acknowledge(); + } + connection.close(); + } + + + @org.junit.Test + public void testValidateRedeliveryFlagAfterTransientFailureConnectionDrop() throws Exception { + + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString() + + "?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination destination = session.createQueue(queueName); + populateDestination(10, destination, connection, true); + TextMessage msg = null; + MessageConsumer consumer = session.createConsumer(destination); + Exception expectedException = null; + try { + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(5000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertTrue("Should not receive the 5th message", i < 4); + //The first 4 messages will be ok but the 5th one should hit an exception in updateMessage and should not be delivered + } + } catch (Exception e) { + //Expecting an exception and disconnect on the 5th message + LOG.info("Got expected:", e); + expectedException = e; + } + assertNotNull("Expecting an exception when updateMessage fails", expectedException); + + consumer.close(); + connection.close(); + + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = session.createQueue(queueName); + consumer = session.createConsumer(destination); + + + // consume the messages that were previously delivered + for (int i = 0; i < 4; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("redelivered? got: " + msg); + assertNotNull("got the message again", msg); + assertEquals("re delivery flag on:" + i, true, msg.getJMSRedelivered()); + assertTrue("redelivery count survives reconnect for:" + i, msg.getLongProperty("JMSXDeliveryCount") > 1); + msg.acknowledge(); + } + + + // consume the rest that were not redeliveries + for (int i = 0; i < 6; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + msg.acknowledge(); + } + connection.close(); + } + + @org.junit.Test + public void testValidateRedeliveryFlagOnNonPersistentAfterTransientFailureConnectionDrop() throws Exception { + + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString() + + "?jms.prefetchPolicy.all=0"); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination destination = session.createQueue(queueName); + populateDestination(10, destination, connection, false); + TextMessage msg = null; + MessageConsumer consumer = session.createConsumer(destination); + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(5000); + assertNotNull("got the message", msg); + assertFalse("not redelivered", msg.getJMSRedelivered()); + } + + connection.getTransport().narrow(TcpTransport.class).getTransportListener().onException(new IOException("Die")); + + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = session.createQueue(queueName); + consumer = session.createConsumer(destination); + + // consume the messages that were previously delivered + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("redelivered? got: " + msg); + assertNotNull("got the message again", msg); + assertEquals("redelivery flag set on:" + i, true, msg.getJMSRedelivered()); + assertTrue("redelivery count survives reconnect for:" + i, msg.getLongProperty("JMSXDeliveryCount") > 1); + msg.acknowledge(); + } + + // consume the rest that were not redeliveries + for (int i = 0; i < 5; i++) { + msg = (TextMessage) consumer.receive(4000); + LOG.info("not redelivered? got: " + msg); + assertNotNull("got the message", msg); + assertEquals("not a redelivery", false, msg.getJMSRedelivered()); + assertEquals("first delivery", 1, msg.getLongProperty("JMSXDeliveryCount")); + msg.acknowledge(); + } + connection.close(); + } + + private void restartBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + broker = createRestartedBroker(); + broker.start(); + } + + private BrokerService createRestartedBroker() throws Exception { + broker = new BrokerService(); + configureBroker(broker, false); + return broker; + } + + private void populateDestination(final int nbMessages, final Destination destination, javax.jms.Connection connection, boolean persistent) throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + for (int i = 1; i <= nbMessages; i++) { + producer.send(session.createTextMessage("")); + } + producer.close(); + session.close(); + } + + private class KahaDBWithUpdateExceptionPersistenceAdapter implements PersistenceAdapter { + + private KahaDBPersistenceAdapter kahaDB = new KahaDBPersistenceAdapter(); + private boolean throwExceptionOnUpdate; + + public KahaDBWithUpdateExceptionPersistenceAdapter(boolean throwExceptionOnUpdate) { + this.throwExceptionOnUpdate = throwExceptionOnUpdate; + } + + @Override + public void start() throws Exception { + kahaDB.start(); + } + + @Override + public void stop() throws Exception { + kahaDB.stop(); + } + + @Override + public Set getDestinations() { + return kahaDB.getDestinations(); + } + + @Override + public MessageStore createQueueMessageStore(ActiveMQQueue destination) + throws IOException { + MessageStore proxyMessageStoreWithException = new ProxyMessageStoreWithUpdateException( + kahaDB.createQueueMessageStore(destination), throwExceptionOnUpdate); + return proxyMessageStoreWithException; + } + + @Override + public TopicMessageStore createTopicMessageStore( + ActiveMQTopic destination) throws IOException { + TopicMessageStore proxyMessageStoreWithException = new ProxyTopicMessageStoreWithUpdateException( + kahaDB.createTopicMessageStore(destination), throwExceptionOnUpdate); + return proxyMessageStoreWithException; + } + + @Override + public JobSchedulerStore createJobSchedulerStore() throws IOException, UnsupportedOperationException { + return kahaDB.createJobSchedulerStore(); + } + + @Override + public void removeQueueMessageStore(ActiveMQQueue destination) { + kahaDB.removeQueueMessageStore(destination); + } + + @Override + public void removeTopicMessageStore(ActiveMQTopic destination) { + kahaDB.removeTopicMessageStore(destination); + } + + @Override + public TransactionStore createTransactionStore() throws IOException { + return kahaDB.createTransactionStore(); + } + + @Override + public void beginTransaction(ConnectionContext context) + throws IOException { + kahaDB.beginTransaction(context); + } + + @Override + public void commitTransaction(ConnectionContext context) + throws IOException { + kahaDB.commitTransaction(context); + } + + @Override + public void rollbackTransaction(ConnectionContext context) + throws IOException { + kahaDB.rollbackTransaction(context); + } + + @Override + public long getLastMessageBrokerSequenceId() throws IOException { + return kahaDB.getLastMessageBrokerSequenceId(); + } + + @Override + public void deleteAllMessages() throws IOException { + kahaDB.deleteAllMessages(); + } + + @Override + public void setUsageManager(SystemUsage usageManager) { + kahaDB.setUsageManager(usageManager); + } + + @Override + public void setBrokerName(String brokerName) { + kahaDB.setBrokerName(brokerName); + } + + @Override + public void setDirectory(File dir) { + kahaDB.setDirectory(dir); + } + + @Override + public File getDirectory() { + return kahaDB.getDirectory(); + } + + @Override + public void checkpoint(boolean sync) throws IOException { + kahaDB.checkpoint(sync); + } + + @Override + public long size() { + return kahaDB.size(); + } + + @Override + public long getLastProducerSequenceId(ProducerId id) throws IOException { + return kahaDB.getLastProducerSequenceId(id); + } + + } + + private class ProxyMessageStoreWithUpdateException extends ProxyMessageStore { + private boolean throwExceptionOnUpdate; + private int numBeforeException = 4; + public ProxyMessageStoreWithUpdateException(MessageStore delegate, boolean throwExceptionOnUpdate) { + super(delegate); + this.throwExceptionOnUpdate = throwExceptionOnUpdate; + } + + @Override + public void updateMessage(Message message) throws IOException { + if(throwExceptionOnUpdate) { + if(numBeforeException > 0) { + numBeforeException--; + super.updateMessage(message); + } else { + // lets only do it once so we can validate transient store failure + throwExceptionOnUpdate = false; + + //A message that has never been delivered will hit this exception + throw new IOException("Hit our simulated exception writing the update to disk"); + } + } else { + super.updateMessage(message); + } + } + } + + private class ProxyTopicMessageStoreWithUpdateException extends ProxyTopicMessageStore { + private boolean throwExceptionOnUpdate; + private int numBeforeException = 4; + public ProxyTopicMessageStoreWithUpdateException(TopicMessageStore delegate, boolean throwExceptionOnUpdate) { + super(delegate); + this.throwExceptionOnUpdate = throwExceptionOnUpdate; + } + + @Override + public void updateMessage(Message message) throws IOException { + if(throwExceptionOnUpdate) { + if(numBeforeException > 0) { + numBeforeException--; + super.updateMessage(message); + } else { + //A message that has never been delivered will hit this exception + throw new IOException("Hit our simulated exception writing the update to disk"); + } + } else { + super.updateMessage(message); + } + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/SpringTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/SpringTest.java new file mode 100644 index 0000000000..7902baa853 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/SpringTest.java @@ -0,0 +1,105 @@ +/** + * 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.broker; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.activemq.spring.SpringConsumer; +import org.apache.activemq.spring.SpringProducer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class SpringTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(SpringTest.class); + + protected AbstractApplicationContext context; + protected SpringConsumer consumer; + protected SpringProducer producer; + + public void testSenderWithSpringXml() throws Exception { + assertSenderConfig("org/apache/activemq/broker/spring.xml"); + } + /** + * assert method that is used by all the test method to send and receive messages + * based on each spring configuration. + * + * @param config + * @throws Exception + */ + protected void assertSenderConfig(String config) throws Exception { + context = new ClassPathXmlApplicationContext(config); + + consumer = (SpringConsumer) context.getBean("consumer"); + assertTrue("Found a valid consumer", consumer != null); + + consumer.start(); + + producer = (SpringProducer) context.getBean("producer"); + assertTrue("Found a valid producer", producer != null); + + consumer.flushMessages(); + producer.start(); + + // lets sleep a little to give the JMS time to dispatch stuff + consumer.waitForMessagesToArrive(producer.getMessageCount()); + + // now lets check that the consumer has received some messages + List messages = consumer.flushMessages(); + LOG.info("Consumer has received messages...."); + for (Iterator iter = messages.iterator(); iter.hasNext();) { + Object message = iter.next(); + LOG.info("Received: " + message); + } + + assertEquals("Message count", producer.getMessageCount(), messages.size()); + } + + /** + * Clean up method. + * + * @throws Exception + */ + protected void tearDown() throws Exception { + if (consumer != null) { + consumer.stop(); + } + if (producer != null) { + producer.stop(); + } + + if (context != null) { + context.destroy(); + } + } + + protected void setUp() throws Exception { + if (System.getProperty("basedir") == null) { + File file = new File("."); + System.setProperty("basedir", file.getAbsolutePath()); + } + super.setUp(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/StubBroker.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/StubBroker.java new file mode 100644 index 0000000000..7b4fa1bbc2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/StubBroker.java @@ -0,0 +1,57 @@ +/** + * 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.broker; + +import java.util.LinkedList; +import org.apache.activemq.command.ConnectionInfo; + +public class StubBroker extends EmptyBroker { + public LinkedList addConnectionData = new LinkedList(); + public LinkedList removeConnectionData = new LinkedList(); + + public class AddConnectionData { + public final ConnectionContext connectionContext; + public final ConnectionInfo connectionInfo; + + public AddConnectionData(ConnectionContext context, ConnectionInfo info) { + connectionContext = context; + connectionInfo = info; + } + } + + public static class RemoveConnectionData { + public final ConnectionContext connectionContext; + public final ConnectionInfo connectionInfo; + public final Throwable error; + + public RemoveConnectionData(ConnectionContext context, ConnectionInfo info, Throwable error) { + connectionContext = context; + connectionInfo = info; + this.error = error; + } + } + + public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { + addConnectionData.add(new AddConnectionData(context, info)); + } + + public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception { + removeConnectionData.add(new RemoveConnectionData(context, info, error)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/StubConnection.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/StubConnection.java new file mode 100644 index 0000000000..9a70c4ee08 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/StubConnection.java @@ -0,0 +1,164 @@ +/** + * 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.broker; + +import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.activemq.Service; +import org.apache.activemq.command.Command; +import org.apache.activemq.command.ExceptionResponse; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.Response; +import org.apache.activemq.command.ShutdownInfo; +import org.apache.activemq.transport.DefaultTransportListener; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.util.JMSExceptionSupport; +import org.apache.activemq.util.ServiceSupport; + +public class StubConnection implements Service { + + private final BlockingQueue dispatchQueue = new LinkedBlockingQueue(); + private Connection connection; + private Transport transport; + private boolean shuttingDown; + private TransportListener listener; + public AtomicReference error = new AtomicReference(); + + public StubConnection(BrokerService broker) throws Exception { + this(TransportFactory.connect(broker.getVmConnectorURI())); + } + + public StubConnection(Connection connection) { + this.connection = connection; + } + + public StubConnection(Transport transport) throws Exception { + this(transport, null); + } + + public StubConnection(Transport transport, TransportListener transportListener) throws Exception { + listener = transportListener; + this.transport = transport; + transport.setTransportListener(new DefaultTransportListener() { + public void onCommand(Object command) { + try { + if (command.getClass() == ShutdownInfo.class) { + shuttingDown = true; + } + StubConnection.this.dispatch(command); + } catch (Exception e) { + onException(new IOException("" + e)); + } + } + + public void onException(IOException e) { + if (listener != null) { + listener.onException(e); + } + error.set(e); + } + }); + transport.start(); + } + + protected void dispatch(Object command) throws InterruptedException, IOException { + if (listener != null) { + listener.onCommand(command); + } + dispatchQueue.put(command); + } + + public BlockingQueue getDispatchQueue() { + return dispatchQueue; + } + + public void send(Command command) throws Exception { + if (command instanceof Message) { + Message message = (Message)command; + message.setProducerId(message.getMessageId().getProducerId()); + } + command.setResponseRequired(false); + if (connection != null) { + Response response = connection.service(command); + if (response != null && response.isException()) { + ExceptionResponse er = (ExceptionResponse)response; + throw JMSExceptionSupport.create(er.getException()); + } + } else if (transport != null) { + transport.oneway(command); + } + } + + public Response request(Command command) throws Exception { + if (command instanceof Message) { + Message message = (Message)command; + message.setProducerId(message.getMessageId().getProducerId()); + } + command.setResponseRequired(true); + if (connection != null) { + Response response = connection.service(command); + if (response != null && response.isException()) { + ExceptionResponse er = (ExceptionResponse)response; + throw JMSExceptionSupport.create(er.getException()); + } + return response; + } else if (transport != null) { + Response response = (Response)transport.request(command); + if (response != null && response.isException()) { + ExceptionResponse er = (ExceptionResponse)response; + throw JMSExceptionSupport.create(er.getException()); + } + return response; + } + return null; + } + + public Connection getConnection() { + return connection; + } + + public Transport getTransport() { + return transport; + } + + public void start() throws Exception { + } + + public void stop() throws Exception { + shuttingDown = true; + if (transport != null) { + try { + transport.oneway(new ShutdownInfo()); + } catch (IOException e) { + } + ServiceSupport.dispose(transport); + } + } + + public TransportListener getListener() { + return listener; + } + + public void setListener(TransportListener listener) { + this.listener = listener; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/TopicSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/TopicSubscriptionTest.java new file mode 100644 index 0000000000..61ba79c96d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/TopicSubscriptionTest.java @@ -0,0 +1,160 @@ +/** + * 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.broker; + +import java.util.concurrent.TimeUnit; +import org.apache.activemq.TestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.util.ThreadTracker; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import static org.junit.Assert.*; + + +@RunWith(BlockJUnit4ClassRunner.class) +public class TopicSubscriptionTest extends QueueSubscriptionTest { + + @Before + public void setUp() throws Exception { + super.setUp(); + durable = true; + topic = true; + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + ThreadTracker.result(); + } + + @Test(timeout = 60 * 1000) + public void testManyProducersManyConsumers() throws Exception { + consumerCount = 40; + producerCount = 20; + messageCount = 100; + messageSize = 1; + prefetchCount = 10; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount * consumerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersLargeMessagesOnePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + messageCount = 10; + messageSize = 1024 * 1024 * 1; // 1 MB + prefetchCount = 1; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * consumerCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersSmallMessagesOnePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + prefetchCount = 1; + messageSize = 1024; + messageCount = 1000; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * consumerCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersSmallMessagesLargePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + messageCount = 1000; + messageSize = 1024; + prefetchCount = messageCount * 2; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * consumerCount * producerCount); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersLargeMessagesLargePrefetch() throws Exception { + consumerCount = 2; + producerCount = 1; + messageCount = 10; + messageSize = 1024 * 1024 * 1; // 1 MB + prefetchCount = messageCount * 2; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * consumerCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerManyConsumersFewMessages() throws Exception { + consumerCount = 50; + producerCount = 1; + messageCount = 10; + messageSize = 1; // 1 byte + prefetchCount = 10; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * consumerCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerManyConsumersManyMessages() throws Exception { + consumerCount = 50; + producerCount = 1; + messageCount = 100; + messageSize = 1; // 1 byte + prefetchCount = 10; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * consumerCount * producerCount); + assertDestinationMemoryUsageGoesToZero(); + } + + + @Test(timeout = 60 * 1000) + public void testManyProducersOneConsumer() throws Exception { + consumerCount = 1; + producerCount = 20; + messageCount = 100; + messageSize = 1; // 1 byte + prefetchCount = 10; + + doMultipleClientsTest(); + + assertTotalMessagesReceived(messageCount * producerCount * consumerCount); + assertDestinationMemoryUsageGoesToZero(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/XARecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/XARecoveryBrokerTest.java new file mode 100644 index 0000000000..2c4167359a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/XARecoveryBrokerTest.java @@ -0,0 +1,1246 @@ +/** + * 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.broker; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import javax.jms.JMSException; +import javax.management.InstanceNotFoundException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import junit.framework.Test; +import org.apache.activemq.broker.jmx.BrokerMBeanSupport; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.broker.jmx.PersistenceAdapterViewMBean; +import org.apache.activemq.broker.jmx.RecoveredXATransactionViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.command.*; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.JMXSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Used to simulate the recovery that occurs when a broker shuts down. + * + * + */ +public class XARecoveryBrokerTest extends BrokerRestartTestSupport { + protected static final Logger LOG = LoggerFactory.getLogger(XARecoveryBrokerTest.class); + public boolean prioritySupport = false; + + public void testPreparedJmxView() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Prepare 4 message sends. + for (int i = 0; i < 4; i++) { + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + + // Prepare + connection.send(createPrepareTransaction(connectionInfo, txid)); + } + + Response response = connection.request(new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER)); + assertNotNull(response); + DataArrayResponse dar = (DataArrayResponse)response; + assertEquals(4, dar.getData().length); + + // view prepared in kahadb view + if (broker.getPersistenceAdapter() instanceof KahaDBPersistenceAdapter) { + PersistenceAdapterViewMBean kahadbView = getProxyToPersistenceAdapter(broker.getPersistenceAdapter().toString()); + String txFromView = kahadbView.getTransactions(); + LOG.info("Tx view fromm PA:" + txFromView); + assertTrue("xid with our dud format in transaction string " + txFromView, txFromView.contains("XID:[55,")); + } + + // restart the broker. + restartBroker(); + + connection = createConnection(); + connectionInfo = createConnectionInfo(); + connection.send(connectionInfo); + + + response = connection.request(new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER)); + assertNotNull(response); + dar = (DataArrayResponse)response; + assertEquals(4, dar.getData().length); + + // validate destination depth via jmx + DestinationViewMBean destinationView = getProxyToDestination(destinationList(destination)[0]); + assertEquals("enqueue count does not see prepared", 0, destinationView.getQueueSize()); + + TransactionId first = (TransactionId)dar.getData()[0]; + int commitCount = 0; + // via jmx, force outcome + for (int i = 0; i < 4; i++) { + RecoveredXATransactionViewMBean mbean = getProxyToPreparedTransactionViewMBean((TransactionId)dar.getData()[i]); + if (i%2==0) { + mbean.heuristicCommit(); + commitCount++; + } else { + mbean.heuristicRollback(); + } + } + + // verify all completed + response = connection.request(new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER)); + assertNotNull(response); + dar = (DataArrayResponse)response; + assertEquals(0, dar.getData().length); + + // verify messages available + assertEquals("enqueue count reflects outcome", commitCount, destinationView.getQueueSize()); + + // verify mbeans gone + try { + RecoveredXATransactionViewMBean gone = getProxyToPreparedTransactionViewMBean(first); + gone.heuristicRollback(); + fail("Excepted not found"); + } catch (InstanceNotFoundException expectedNotfound) { + } + } + + private PersistenceAdapterViewMBean getProxyToPersistenceAdapter(String name) throws MalformedObjectNameException, JMSException { + return (PersistenceAdapterViewMBean)broker.getManagementContext().newProxyInstance( + BrokerMBeanSupport.createPersistenceAdapterName(broker.getBrokerObjectName().toString(), name), + PersistenceAdapterViewMBean.class, true); + } + + private RecoveredXATransactionViewMBean getProxyToPreparedTransactionViewMBean(TransactionId xid) throws MalformedObjectNameException, JMSException { + + ObjectName objectName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,transactionType=RecoveredXaTransaction,xid=" + + JMXSupport.encodeObjectNamePart(xid.toString())); + RecoveredXATransactionViewMBean proxy = (RecoveredXATransactionViewMBean) broker.getManagementContext().newProxyInstance(objectName, + RecoveredXATransactionViewMBean.class, true); + return proxy; + } + + private DestinationViewMBean getProxyToDestination(ActiveMQDestination destination) throws MalformedObjectNameException, JMSException { + + final ObjectName objectName = new ObjectName("org.apache.activemq:type=Broker,brokerName="+broker.getBrokerName()+",destinationType=" + + JMXSupport.encodeObjectNamePart(destination.getDestinationTypeAsString()) + + ",destinationName=" + JMXSupport.encodeObjectNamePart(destination.getPhysicalName())); + + DestinationViewMBean proxy = (DestinationViewMBean) broker.getManagementContext().newProxyInstance(objectName, + DestinationViewMBean.class, true); + return proxy; + + } + + public void testPreparedTransactionRecoveredOnRestart() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Prepare 4 message sends. + for (int i = 0; i < 4; i++) { + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + + // Prepare + connection.send(createPrepareTransaction(connectionInfo, txid)); + } + + // Since prepared but not committed.. they should not get delivered. + assertNull(receiveMessage(connection)); + assertNoMessagesLeft(connection); + connection.request(closeConnectionInfo(connectionInfo)); + + // restart the broker. + restartBroker(); + + // Setup the consumer and try receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Since prepared but not committed.. they should not get delivered. + assertNull(receiveMessage(connection)); + assertNoMessagesLeft(connection); + + Response response = connection.request(new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER)); + assertNotNull(response); + DataArrayResponse dar = (DataArrayResponse)response; + assertEquals(4, dar.getData().length); + + // ensure we can close a connection with prepared transactions + connection.request(closeConnectionInfo(connectionInfo)); + + // open again to deliver outcome + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Commit the prepared transactions. + for (int i = 0; i < dar.getData().length; i++) { + TransactionId transactionId = (TransactionId) dar.getData()[i]; + LOG.info("commit: " + transactionId); + connection.request(createCommitTransaction2Phase(connectionInfo, transactionId)); + } + + // We should get the committed transactions. + final int countToReceive = expectedMessageCount(4, destination); + for (int i = 0; i < countToReceive ; i++) { + Message m = receiveMessage(connection, TimeUnit.SECONDS.toMillis(10)); + LOG.info("received: " + m); + assertNotNull("Got non null message: " + i, m); + } + + assertNoMessagesLeft(connection); + assertEmptyDLQ(); + } + + private void assertEmptyDLQ() throws Exception { + try { + DestinationViewMBean destinationView = getProxyToDestination(new ActiveMQQueue(SharedDeadLetterStrategy.DEFAULT_DEAD_LETTER_QUEUE_NAME)); + assertEquals("nothing on dlq", 0, destinationView.getQueueSize()); + assertEquals("nothing added to dlq", 0, destinationView.getEnqueueCount()); + } catch (java.lang.reflect.UndeclaredThrowableException maybeOk) { + if (maybeOk.getUndeclaredThrowable() instanceof javax.management.InstanceNotFoundException) { + // perfect no dlq + } else { + throw maybeOk; + } + } + } + + public void testPreparedInterleavedTransactionRecoveredOnRestart() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // Prepare 4 message sends. + for (int i = 0; i < 4; i++) { + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + + // Prepare + connection.send(createPrepareTransaction(connectionInfo, txid)); + } + + // Since prepared but not committed.. they should not get delivered. + assertNull(receiveMessage(connection)); + assertNoMessagesLeft(connection); + + // send non tx message + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.request(message); + + connection.request(closeConnectionInfo(connectionInfo)); + + // restart the broker. + restartBroker(); + + // Setup the consumer and try receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // consume non transacted message, but don't ack + int countToReceive = expectedMessageCount(1, destination); + for (int i=0; i< countToReceive; i++) { + Message m = receiveMessage(connection, TimeUnit.SECONDS.toMillis(10)); + LOG.info("received: " + m); + assertNotNull("got non tx message after prepared", m); + } + + // Since prepared but not committed.. they should not get delivered. + assertNull(receiveMessage(connection)); + assertNoMessagesLeft(connection); + + Response response = connection.request(new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER)); + assertNotNull(response); + DataArrayResponse dar = (DataArrayResponse)response; + assertEquals(4, dar.getData().length); + + // ensure we can close a connection with prepared transactions + connection.request(closeConnectionInfo(connectionInfo)); + + // open again to deliver outcome + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + + // Commit the prepared transactions. + for (int i = 0; i < dar.getData().length; i++) { + TransactionId transactionId = (TransactionId) dar.getData()[i]; + LOG.info("commit: " + transactionId); + connection.request(createCommitTransaction2Phase(connectionInfo, transactionId)); + } + + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // We should get the committed transactions and the non tx message + countToReceive = expectedMessageCount(5, destination); + for (int i = 0; i < countToReceive ; i++) { + Message m = receiveMessage(connection, TimeUnit.SECONDS.toMillis(10)); + LOG.info("received: " + m); + assertNotNull("Got non null message: " + i, m); + } + + assertNoMessagesLeft(connection); + assertEmptyDLQ(); + } + + public void testTopicPreparedTransactionRecoveredOnRestart() throws Exception { + ActiveMQDestination destination = new ActiveMQTopic("TryTopic"); + + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + // Prepare 4 message sends. + for (int i = 0; i < 4; i++) { + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + + // Prepare + connection.send(createPrepareTransaction(connectionInfo, txid)); + } + + // Since prepared but not committed.. they should not get delivered. + assertNull(receiveMessage(connection)); + assertNoMessagesLeft(connection); + connection.request(closeConnectionInfo(connectionInfo)); + + // restart the broker. + restartBroker(); + + // Setup the consumer and try receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + // Since prepared but not committed.. they should not get delivered. + assertNull(receiveMessage(connection)); + assertNoMessagesLeft(connection); + + Response response = connection.request(new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER)); + assertNotNull(response); + DataArrayResponse dar = (DataArrayResponse) response; + assertEquals(4, dar.getData().length); + + // ensure we can close a connection with prepared transactions + connection.request(closeConnectionInfo(connectionInfo)); + + // open again to deliver outcome + connection = createConnection(); + connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + // Commit the prepared transactions. + for (int i = 0; i < dar.getData().length; i++) { + connection.request(createCommitTransaction2Phase(connectionInfo, (TransactionId) dar.getData()[i])); + } + + // We should get the committed transactions. + for (int i = 0; i < expectedMessageCount(4, destination); i++) { + Message m = receiveMessage(connection, TimeUnit.SECONDS.toMillis(10)); + assertNotNull(m); + } + + assertNoMessagesLeft(connection); + + } + + public void testQueuePersistentCommitedMessagesNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + } + + // Commit + connection.send(createCommitTransaction1Phase(connectionInfo, txid)); + connection.request(closeConnectionInfo(connectionInfo)); + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + for (int i = 0; i < expectedMessageCount(4, destination); i++) { + Message m = receiveMessage(connection); + assertNotNull(m); + } + + assertNoMessagesLeft(connection); + } + + public void testQueuePersistentCommited2PhaseMessagesNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + } + + // Commit 2 phase + connection.request(createPrepareTransaction(connectionInfo, txid)); + connection.send(createCommitTransaction2Phase(connectionInfo, txid)); + + connection.request(closeConnectionInfo(connectionInfo)); + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + for (int i = 0; i < expectedMessageCount(4, destination); i++) { + Message m = receiveMessage(connection); + assertNotNull(m); + } + + assertNoMessagesLeft(connection); + } + + public void testQueuePersistentCommitedAcksNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + ConsumerInfo consumerInfo; + Message m = null; + for (ActiveMQDestination dest : destinationList(destination)) { + // Setup the consumer and receive the message. + consumerInfo = createConsumerInfo(sessionInfo, dest); + connection.send(consumerInfo); + + for (int i = 0; i < 4; i++) { + m = receiveMessage(connection); + assertNotNull(m); + } + + MessageAck ack = createAck(consumerInfo, m, 4, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + + // Commit + connection.request(createCommitTransaction1Phase(connectionInfo, txid)); + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // No messages should be delivered. + assertNoMessagesLeft(connection); + + m = receiveMessage(connection); + assertNull(m); + } + + public void testQueuePersistentPreparedAcksNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + ConsumerInfo consumerInfo; + Message m = null; + for (ActiveMQDestination dest : destinationList(destination)) { + // Setup the consumer and receive the message. + consumerInfo = createConsumerInfo(sessionInfo, dest); + connection.send(consumerInfo); + + for (int i = 0; i < 4; i++) { + m = receiveMessage(connection); + assertNotNull(m); + } + + // one ack with last received, mimic a beforeEnd synchronization + MessageAck ack = createAck(consumerInfo, m, 4, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + + connection.request(createPrepareTransaction(connectionInfo, txid)); + + // restart the broker. + restartBroker(); + + connection = createConnection(); + connectionInfo = createConnectionInfo(); + connection.send(connectionInfo); + + // validate recovery + TransactionInfo recoverInfo = new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER); + DataArrayResponse dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + + assertEquals("there is a prepared tx", 1, dataArrayResponse.getData().length); + assertEquals("it matches", txid, dataArrayResponse.getData()[0]); + + sessionInfo = createSessionInfo(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // no redelivery, exactly once semantics unless there is rollback + m = receiveMessage(connection); + assertNull(m); + assertNoMessagesLeft(connection); + + // validate destination depth via jmx + DestinationViewMBean destinationView = getProxyToDestination(destinationList(destination)[0]); + assertEquals("enqueue count does not see prepared acks", 4, destinationView.getQueueSize()); + assertEquals("enqueue count does not see prepared acks", 0, destinationView.getDequeueCount()); + + connection.request(createCommitTransaction2Phase(connectionInfo, txid)); + + // validate recovery complete + dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + assertEquals("there are no prepared tx", 0, dataArrayResponse.getData().length); + + assertEquals("enqueue count does not see commited acks", 0, destinationView.getQueueSize()); + assertEquals("enqueue count does not see commited acks", 4, destinationView.getDequeueCount()); + + } + + public void initCombosForTestTopicPersistentPreparedAcksNotLostOnRestart() { + addCombinationValues("prioritySupport", new Boolean[]{Boolean.FALSE, Boolean.TRUE}); + } + + public void testTopicPersistentPreparedAcksNotLostOnRestart() throws Exception { + ActiveMQDestination destination = new ActiveMQTopic("TryTopic"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // setup durable subs + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + final int numMessages = 4; + for (int i = 0; i < numMessages; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + final int messageCount = expectedMessageCount(numMessages, destination); + Message m = null; + for (int i = 0; i < messageCount; i++) { + m = receiveMessage(connection); + assertNotNull("unexpected null on: " + i, m); + } + + // one ack with last received, mimic a beforeEnd synchronization + MessageAck ack = createAck(consumerInfo, m, messageCount, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + + connection.request(createPrepareTransaction(connectionInfo, txid)); + + // restart the broker. + restartBroker(); + + connection = createConnection(); + connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + connection.send(connectionInfo); + + // validate recovery + TransactionInfo recoverInfo = new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER); + DataArrayResponse dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + + assertEquals("there is a prepared tx", 1, dataArrayResponse.getData().length); + assertEquals("it matches", txid, dataArrayResponse.getData()[0]); + + sessionInfo = createSessionInfo(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + // no redelivery, exactly once semantics unless there is rollback + m = receiveMessage(connection); + assertNull(m); + assertNoMessagesLeft(connection); + + connection.request(createCommitTransaction2Phase(connectionInfo, txid)); + + // validate recovery complete + dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + assertEquals("there are no prepared tx", 0, dataArrayResponse.getData().length); + } + + public void testQueuePersistentPreparedAcksAvailableAfterRestartAndRollback() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + int numMessages = 4; + for (int i = 0; i < numMessages; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + ConsumerInfo consumerInfo; + Message message = null; + for (ActiveMQDestination dest : destinationList(destination)) { + // Setup the consumer and receive the message. + consumerInfo = createConsumerInfo(sessionInfo, dest); + connection.send(consumerInfo); + + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull(message); + } + + // one ack with last received, mimic a beforeEnd synchronization + MessageAck ack = createAck(consumerInfo, message, numMessages, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + + connection.request(createPrepareTransaction(connectionInfo, txid)); + + // restart the broker. + restartBroker(); + + connection = createConnection(); + connectionInfo = createConnectionInfo(); + connection.send(connectionInfo); + + // validate recovery + TransactionInfo recoverInfo = new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER); + DataArrayResponse dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + + assertEquals("there is a prepared tx", 1, dataArrayResponse.getData().length); + assertEquals("it matches", txid, dataArrayResponse.getData()[0]); + + sessionInfo = createSessionInfo(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + // no redelivery, exactly once semantics while prepared + message = receiveMessage(connection); + assertNull(message); + assertNoMessagesLeft(connection); + + // rollback so we get redelivery + connection.request(createRollbackTransaction(connectionInfo, txid)); + + LOG.info("new tx for redelivery"); + txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (ActiveMQDestination dest : destinationList(destination)) { + // Setup the consumer and receive the message. + consumerInfo = createConsumerInfo(sessionInfo, dest); + connection.send(consumerInfo); + + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull("unexpected null on:" + i, message); + } + MessageAck ack = createAck(consumerInfo, message, numMessages, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + + // Commit + connection.request(createCommitTransaction1Phase(connectionInfo, txid)); + + // validate recovery complete + dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + assertEquals("there are no prepared tx", 0, dataArrayResponse.getData().length); + } + + public void testQueuePersistentPreparedAcksAvailableAfterRollbackPrefetchOne() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + int numMessages = 1; + for (int i = 0; i < numMessages; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + final int messageCount = expectedMessageCount(numMessages, destination); + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + // use consumer per destination for the composite dest case + // bc the same composite dest is used for sending so there + // will be duplicate message ids in the mix which a single + // consumer (PrefetchSubscription) cannot handle in a tx + // atm. The matching is based on messageId rather than messageId + // and destination + Set consumerInfos = new HashSet(); + for (ActiveMQDestination dest : destinationList(destination)) { + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, dest); + consumerInfo.setPrefetchSize(numMessages); + consumerInfos.add(consumerInfo); + } + + for (ConsumerInfo info : consumerInfos) { + connection.send(info); + } + + Message message = null; + for (ConsumerInfo info : consumerInfos) { + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull(message); + connection.send(createAck(info, message, 1, MessageAck.DELIVERED_ACK_TYPE)); + } + MessageAck ack = createAck(info, message, numMessages, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + connection.request(createPrepareTransaction(connectionInfo, txid)); + + // reconnect + connection.send(connectionInfo.createRemoveCommand()); + connection = createConnection(); + connection.send(connectionInfo); + + // validate recovery + TransactionInfo recoverInfo = new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER); + DataArrayResponse dataArrayResponse = (DataArrayResponse) connection.request(recoverInfo); + + assertEquals("there is a prepared tx", 1, dataArrayResponse.getData().length); + assertEquals("it matches", txid, dataArrayResponse.getData()[0]); + + connection.send(sessionInfo); + + for (ConsumerInfo info : consumerInfos) { + connection.send(info); + } + + // no redelivery, exactly once semantics while prepared + message = receiveMessage(connection); + assertNull(message); + assertNoMessagesLeft(connection); + + // rollback so we get redelivery + connection.request(createRollbackTransaction(connectionInfo, txid)); + + LOG.info("new tx for redelivery"); + txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (ConsumerInfo info : consumerInfos) { + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull("unexpected null on:" + i, message); + MessageAck ack = createAck(info, message, 1, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + } + } + + // Commit + connection.request(createCommitTransaction1Phase(connectionInfo, txid)); + + // validate recovery complete + dataArrayResponse = (DataArrayResponse) connection.request(recoverInfo); + assertEquals("there are no prepared tx", 0, dataArrayResponse.getData().length); + } + + public void initCombosForTestTopicPersistentPreparedAcksAvailableAfterRestartAndRollback() { + addCombinationValues("prioritySupport", new Boolean[]{Boolean.FALSE, Boolean.TRUE}); + } + + public void testTopicPersistentPreparedAcksAvailableAfterRestartAndRollback() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TryTopic"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // setup durable subs + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + int numMessages = 4; + for (int i = 0; i < numMessages; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + Message message = null; + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull(message); + } + + // one ack with last received, mimic a beforeEnd synchronization + MessageAck ack = createAck(consumerInfo, message, numMessages, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + + connection.request(createPrepareTransaction(connectionInfo, txid)); + + // restart the broker. + restartBroker(); + + connection = createConnection(); + connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + connection.send(connectionInfo); + + // validate recovery + TransactionInfo recoverInfo = new TransactionInfo(connectionInfo.getConnectionId(), null, TransactionInfo.RECOVER); + DataArrayResponse dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + + assertEquals("there is a prepared tx", 1, dataArrayResponse.getData().length); + assertEquals("it matches", txid, dataArrayResponse.getData()[0]); + + sessionInfo = createSessionInfo(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + // no redelivery, exactly once semantics while prepared + message = receiveMessage(connection); + assertNull(message); + assertNoMessagesLeft(connection); + + // rollback so we get redelivery + connection.request(createRollbackTransaction(connectionInfo, txid)); + + LOG.info("new tx for redelivery"); + txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull("unexpected null on:" + i, message); + } + ack = createAck(consumerInfo, message, numMessages, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + + // Commit + connection.request(createCommitTransaction1Phase(connectionInfo, txid)); + + // validate recovery complete + dataArrayResponse = (DataArrayResponse)connection.request(recoverInfo); + assertEquals("there are no prepared tx", 0, dataArrayResponse.getData().length); + } + + public void initCombosForTestTopicPersistentPreparedAcksAvailableAfterRollback() { + addCombinationValues("prioritySupport", new Boolean[]{Boolean.FALSE, Boolean.TRUE}); + } + + public void testTopicPersistentPreparedAcksAvailableAfterRollback() throws Exception { + + ActiveMQDestination destination = new ActiveMQTopic("TryTopic"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + // setup durable subs + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + int numMessages = 4; + for (int i = 0; i < numMessages; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + Message message = null; + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull(message); + } + + // one ack with last received, mimic a beforeEnd synchronization + MessageAck ack = createAck(consumerInfo, message, numMessages, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + + connection.request(createPrepareTransaction(connectionInfo, txid)); + + // rollback so we get redelivery + connection.request(createRollbackTransaction(connectionInfo, txid)); + + LOG.info("new consumer/tx for redelivery"); + connection.request(closeConnectionInfo(connectionInfo)); + + connectionInfo = createConnectionInfo(); + connectionInfo.setClientId("durable"); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + + // setup durable subs + consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setSubscriptionName("durable"); + connection.send(consumerInfo); + + txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + for (int i = 0; i < numMessages; i++) { + message = receiveMessage(connection); + assertNotNull("unexpected null on:" + i, message); + } + ack = createAck(consumerInfo, message, numMessages, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.send(ack); + + // Commit + connection.request(createCommitTransaction1Phase(connectionInfo, txid)); + } + + private ActiveMQDestination[] destinationList(ActiveMQDestination dest) { + return dest.isComposite() ? dest.getCompositeDestinations() : new ActiveMQDestination[]{dest}; + } + + private int expectedMessageCount(int i, ActiveMQDestination destination) { + return i * (destination.isComposite() ? destination.getCompositeDestinations().length : 1); + } + + public void testQueuePersistentUncommittedAcksLostOnRestart() throws Exception { + + ActiveMQDestination destination = createDestination(); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + for (int i = 0; i < 4; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + } + + // Begin the transaction. + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + + Message message = null; + for (ActiveMQDestination dest : destinationList(destination)) { + // Setup the consumer and receive the message. + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, dest); + connection.send(consumerInfo); + + for (int i = 0; i < 4; i++) { + message = receiveMessage(connection); + assertNotNull(message); + } + MessageAck ack = createAck(consumerInfo, message, 4, MessageAck.STANDARD_ACK_TYPE); + ack.setTransactionId(txid); + connection.request(ack); + } + + // Don't commit + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + + for (ActiveMQDestination dest : destinationList(destination)) { + // Setup the consumer and receive the message. + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, dest); + connection.send(consumerInfo); + + for (int i = 0; i < 4; i++) { + message = receiveMessage(connection); + assertNotNull(message); + } + } + + assertNoMessagesLeft(connection); + } + + @Override + protected PolicyEntry getDefaultPolicy() { + PolicyEntry policyEntry = super.getDefaultPolicy(); + policyEntry.setPrioritizedMessages(prioritySupport); + return policyEntry; + } + + public static Test suite() { + return suite(XARecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + protected ActiveMQDestination createDestination() { + return new ActiveMQQueue(getClass().getName() + "." + getName()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryBrokerTest.java new file mode 100644 index 0000000000..c65dc53931 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryBrokerTest.java @@ -0,0 +1,330 @@ +/** + * 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.broker.advisory; + +import junit.framework.Test; + +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerTestSupport; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.RemoveInfo; +import org.apache.activemq.command.SessionInfo; + +public class AdvisoryBrokerTest extends BrokerTestSupport { + + public void testConnectionAdvisories() throws Exception { + + ActiveMQDestination destination = AdvisorySupport.getConnectionAdvisoryTopic(); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(consumerInfo1); + + // We should get an advisory of our own connection. + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ConnectionInfo)m1.getDataStructure()).getConnectionId(), connectionInfo1.getConnectionId()); + + // Setup a second connection + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + connection2.send(connectionInfo2); + + // We should get an advisory of the second connection. + m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ConnectionInfo)m1.getDataStructure()).getConnectionId(), connectionInfo2.getConnectionId()); + + // Close the second connection. + connection2.send(closeConnectionInfo(connectionInfo2)); + connection2.stop(); + + // We should get an advisory of the second connection closing + m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + RemoveInfo r = (RemoveInfo) m1.getDataStructure(); + assertEquals(r.getObjectId(), connectionInfo2.getConnectionId()); + + assertNoMessagesLeft(connection1); + } + + public void testConsumerAdvisories() throws Exception { + + ActiveMQDestination queue = new ActiveMQQueue("test"); + ActiveMQDestination destination = AdvisorySupport.getConsumerAdvisoryTopic(queue); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(consumerInfo1); + + // We should not see and advisory for the advisory consumer. + assertNoMessagesLeft(connection1); + + // Setup a second consumer. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, queue); + consumerInfo1.setPrefetchSize(100); + + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(consumerInfo2); + + // We should get an advisory of the new consumer. + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ConsumerInfo)m1.getDataStructure()).getConsumerId(), consumerInfo2.getConsumerId()); + + // Close the second connection. + connection2.request(closeConnectionInfo(connectionInfo2)); + connection2.stop(); + + // We should get an advisory of the consumer closing + m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + RemoveInfo r = (RemoveInfo) m1.getDataStructure(); + assertEquals(r.getObjectId(), consumerInfo2.getConsumerId()); + + assertNoMessagesLeft(connection2); + } + + public void testConsumerAdvisoriesReplayed() throws Exception { + + ActiveMQDestination queue = new ActiveMQQueue("test"); + ActiveMQDestination destination = AdvisorySupport.getConsumerAdvisoryTopic(queue); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + + // Setup a second consumer. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, queue); + consumerInfo2.setPrefetchSize(100); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(consumerInfo2); + + // We should get an advisory of the previous consumer. + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ConsumerInfo)m1.getDataStructure()).getConsumerId(), consumerInfo2.getConsumerId()); + + // Close the second connection. + connection2.request(closeConnectionInfo(connectionInfo2)); + connection2.stop(); + + // We should get an advisory of the consumer closing + m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + RemoveInfo r = (RemoveInfo) m1.getDataStructure(); + assertEquals(r.getObjectId(), consumerInfo2.getConsumerId()); + + assertNoMessagesLeft(connection2); + } + + + public void testProducerAdvisories() throws Exception { + + ActiveMQDestination queue = new ActiveMQQueue("test"); + ActiveMQDestination destination = AdvisorySupport.getProducerAdvisoryTopic(queue); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(consumerInfo1); + + assertNoMessagesLeft(connection1); + + // Setup a producer. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + producerInfo2.setDestination(queue); + + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(producerInfo2); + + // We should get an advisory of the new produver. + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ProducerInfo)m1.getDataStructure()).getProducerId(), producerInfo2.getProducerId()); + + // Close the second connection. + connection2.request(closeConnectionInfo(connectionInfo2)); + connection2.stop(); + + // We should get an advisory of the producer closing + m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + RemoveInfo r = (RemoveInfo) m1.getDataStructure(); + assertEquals(r.getObjectId(), producerInfo2.getProducerId()); + + assertNoMessagesLeft(connection2); + } + + public void testProducerAdvisoriesReplayed() throws Exception { + + ActiveMQDestination queue = new ActiveMQQueue("test"); + ActiveMQDestination destination = AdvisorySupport.getProducerAdvisoryTopic(queue); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + + // Setup a producer. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + producerInfo2.setDestination(queue); + + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(producerInfo2); + + // Create the advisory consumer.. it should see the previous producer + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ProducerInfo)m1.getDataStructure()).getProducerId(), producerInfo2.getProducerId()); + + // Close the second connection. + connection2.request(closeConnectionInfo(connectionInfo2)); + connection2.stop(); + + // We should get an advisory of the producer closing + m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + RemoveInfo r = (RemoveInfo) m1.getDataStructure(); + assertEquals(r.getObjectId(), producerInfo2.getProducerId()); + + assertNoMessagesLeft(connection2); + } + + public void testProducerAdvisoriesReplayedOnlyTargetNewConsumer() throws Exception { + + ActiveMQDestination queue = new ActiveMQQueue("test"); + ActiveMQDestination destination = AdvisorySupport.getProducerAdvisoryTopic(queue); + + // Setup a first connection + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + // Create the first consumer.. + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + consumerInfo1.setPrefetchSize(100); + connection1.send(consumerInfo1); + + // Setup a producer. + StubConnection connection2 = createConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + ProducerInfo producerInfo2 = createProducerInfo(sessionInfo2); + producerInfo2.setDestination(queue); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.send(producerInfo2); + + Message m1 = receiveMessage(connection1); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ProducerInfo)m1.getDataStructure()).getProducerId(), producerInfo2.getProducerId()); + + // Create the 2nd consumer.. + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + consumerInfo2.setPrefetchSize(100); + connection2.send(consumerInfo2); + + // The second consumer should se a replay + m1 = receiveMessage(connection2); + assertNotNull(m1); + assertNotNull(m1.getDataStructure()); + assertEquals(((ProducerInfo)m1.getDataStructure()).getProducerId(), producerInfo2.getProducerId()); + + // But the first consumer should not see the replay. + assertNoMessagesLeft(connection1); + } + + public static Test suite() { + return suite(AdvisoryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryDuplexNetworkBridgeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryDuplexNetworkBridgeTest.java new file mode 100644 index 0000000000..e791fbed76 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryDuplexNetworkBridgeTest.java @@ -0,0 +1,47 @@ +/** + * 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.broker.advisory; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; + +import java.net.URI; + +public class AdvisoryDuplexNetworkBridgeTest extends AdvisoryNetworkBridgeTest { + + @Override + public void createBroker1() throws Exception { + broker1 = new BrokerService(); + broker1.setBrokerName("broker1"); + broker1.addConnector("tcp://localhost:61617"); + broker1.setUseJmx(false); + broker1.setPersistent(false); + broker1.start(); + broker1.waitUntilStarted(); + } + + @Override + public void createBroker2() throws Exception { + broker2 = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/network/duplexLocalBroker.xml")); + broker2.start(); + broker2.waitUntilStarted(); + } + + public void assertCreatedByDuplex(boolean createdByDuplex) { + assertTrue(createdByDuplex); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryJmxTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryJmxTest.java new file mode 100644 index 0000000000..d452bed3aa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryJmxTest.java @@ -0,0 +1,86 @@ +/** + * 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.broker.advisory; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerViewMBean; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.DestinationInfo; + +import javax.jms.*; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +public class AdvisoryJmxTest extends EmbeddedBrokerTestSupport { + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(isPersistent()); + answer.addConnector(bindAddress); + ManagementContext context = new ManagementContext(); + context.setConnectorPort(1199); + answer.setManagementContext(context); + return answer; + } + + public void testCreateDeleteDestinations() throws Exception { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1199/jmxrmi"); + JMXConnector connector = JMXConnectorFactory.connect(url, null); + connector.connect(); + MBeanServerConnection connection = connector.getMBeanServerConnection(); + ObjectName name = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost"); + BrokerViewMBean brokerMbean = (BrokerViewMBean) MBeanServerInvocationHandler.newProxyInstance(connection, name, BrokerViewMBean.class, true); + Connection conn = createConnection(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = sess.createConsumer(sess.createTopic("ActiveMQ.Advisory.Queue")); + conn.start(); + Destination dest = sess.createQueue("test"); + + brokerMbean.addQueue("test"); + + ActiveMQMessage msg = (ActiveMQMessage)consumer.receive(1000); + assertNotNull(msg); + assertTrue(msg.getDataStructure() instanceof DestinationInfo); + assertEquals(((DestinationInfo)msg.getDataStructure()).getDestination(), dest); + assertEquals(((DestinationInfo)msg.getDataStructure()).getOperationType(), 0); + + brokerMbean.removeQueue("test"); + + msg = (ActiveMQMessage)consumer.receive(1000); + assertNotNull(msg); + assertTrue(msg.getDataStructure() instanceof DestinationInfo); + assertEquals(((DestinationInfo)msg.getDataStructure()).getDestination(), dest); + assertEquals(((DestinationInfo)msg.getDataStructure()).getOperationType(), 1); + + + brokerMbean.addQueue("test"); + msg = (ActiveMQMessage)consumer.receive(1000); + assertNotNull(msg); + assertTrue(msg.getDataStructure() instanceof DestinationInfo); + assertEquals(((DestinationInfo)msg.getDataStructure()).getDestination(), dest); + assertEquals(((DestinationInfo)msg.getDataStructure()).getOperationType(), 0); + assertEquals(((DestinationInfo)msg.getDataStructure()).getOperationType(), 0); + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryNetworkBridgeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryNetworkBridgeTest.java new file mode 100644 index 0000000000..da9cc6d053 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryNetworkBridgeTest.java @@ -0,0 +1,128 @@ +/** + * 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.broker.advisory; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.BrokerInfo; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import java.net.URI; + +public class AdvisoryNetworkBridgeTest extends TestCase { + + BrokerService broker1; + BrokerService broker2; + + + public void testAdvisory() throws Exception { + createBroker1(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://broker1"); + Connection conn = factory.createConnection(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + MessageConsumer consumer = sess.createConsumer(AdvisorySupport.getNetworkBridgeAdvisoryTopic()); + + Thread.sleep(1000); + + createBroker2(); + + ActiveMQMessage advisory = (ActiveMQMessage)consumer.receive(2000); + assertNotNull(advisory); + assertTrue(advisory.getDataStructure() instanceof BrokerInfo); + assertTrue(advisory.getBooleanProperty("started")); + assertCreatedByDuplex(advisory.getBooleanProperty("createdByDuplex")); + + broker2.stop(); + broker2.waitUntilStopped(); + + advisory = (ActiveMQMessage)consumer.receive(2000); + assertNotNull(advisory); + assertTrue(advisory.getDataStructure() instanceof BrokerInfo); + assertFalse(advisory.getBooleanProperty("started")); + + conn.close(); + } + + public void testAddConsumerLater() throws Exception { + createBroker1(); + + createBroker2(); + + Thread.sleep(1000); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://broker1"); + Connection conn = factory.createConnection(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + MessageConsumer consumer = sess.createConsumer(AdvisorySupport.getNetworkBridgeAdvisoryTopic()); + + ActiveMQMessage advisory = (ActiveMQMessage)consumer.receive(2000); + assertNotNull(advisory); + assertTrue(advisory.getDataStructure() instanceof BrokerInfo); + assertTrue(advisory.getBooleanProperty("started")); + assertCreatedByDuplex(advisory.getBooleanProperty("createdByDuplex")); + + broker2.stop(); + broker2.waitUntilStopped(); + + advisory = (ActiveMQMessage)consumer.receive(2000); + assertNotNull(advisory); + assertTrue(advisory.getDataStructure() instanceof BrokerInfo); + assertFalse(advisory.getBooleanProperty("started")); + + consumer = sess.createConsumer(AdvisorySupport.getNetworkBridgeAdvisoryTopic()); + advisory = (ActiveMQMessage)consumer.receive(1000); + assertNull(advisory); + + conn.close(); + + } + + public void assertCreatedByDuplex(boolean createdByDuplex) { + assertFalse(createdByDuplex); + } + + public void createBroker1() throws Exception { + broker1 = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/network/reconnect-broker1.xml")); + broker1.start(); + broker1.waitUntilStarted(); + } + + public void createBroker2() throws Exception { + broker2 = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/network/reconnect-broker2.xml")); + broker2.start(); + broker2.waitUntilStarted(); + } + + + @Override + protected void tearDown() throws Exception { + broker1.stop(); + broker1.waitUntilStopped(); + + broker2.stop(); + broker2.waitUntilStopped(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/destinations-on-start.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/destinations-on-start.xml new file mode 100644 index 0000000000..f0ee482b56 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/destinations-on-start.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/exclusive-consumer-startup-destination.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/exclusive-consumer-startup-destination.xml new file mode 100644 index 0000000000..5c10b7db78 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/exclusive-consumer-startup-destination.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveLeaseQuiesceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveLeaseQuiesceTest.java new file mode 100644 index 0000000000..e71cfe6d0d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveLeaseQuiesceTest.java @@ -0,0 +1,80 @@ +/** + * 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.broker.ft; + +import java.util.concurrent.TimeUnit; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.LeaseLockerIOExceptionHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbRestartJDBCQueueMasterSlaveLeaseQuiesceTest extends DbRestartJDBCQueueMasterSlaveLeaseTest { + private static final transient Logger LOG = LoggerFactory.getLogger(DbRestartJDBCQueueMasterSlaveLeaseQuiesceTest.class); + + private long restartDelay = 2000; + + @Override + protected void configureBroker(BrokerService brokerService) { + // master and slave survive db restart and retain master/slave status + LeaseLockerIOExceptionHandler stopConnectors = new LeaseLockerIOExceptionHandler(); + brokerService.setIoExceptionHandler(stopConnectors); + } + + @Override + protected void delayTillRestartRequired() { + if (restartDelay > 2000) { + LOG.info("delay for more than lease quantum. While Db is offline, master should stay alive but could loose lease"); + } else { + LOG.info("delay for less than lease quantum. While Db is offline, master should stay alive"); + } + try { + TimeUnit.MILLISECONDS.sleep(restartDelay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + protected void verifyExpectedBroker(int inflightMessageCount) { + if (inflightMessageCount == 0 || (inflightMessageCount == failureCount + 10 && restartDelay <= 500)) { + assertEquals("connected to master", master.getBrokerName(), ((ActiveMQConnection)sendConnection).getBrokerName()); + } else { + // lease expired while DB was offline, either or master/slave can grab it so assert is not deterministic + // but we still need to validate sent == received + } + } + + @Override + public void setUp() throws Exception { + restartDelay = 2000; + super.setUp(); + } + + public void testSendReceiveWithLeaseExpiry() throws Exception { + restartDelay = 10000; + testSendReceive(); + } + + // ignore this test case + public void testAdvisory() throws Exception {} + + @Override + public void testSendReceive() throws Exception { + // Ignore this test for now, see AMQ-4975 + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveLeaseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveLeaseTest.java new file mode 100644 index 0000000000..cf4929a551 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveLeaseTest.java @@ -0,0 +1,57 @@ +/** + * 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.broker.ft; + +import java.io.IOException; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.jdbc.LeaseDatabaseLocker; +import org.apache.activemq.util.LeaseLockerIOExceptionHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbRestartJDBCQueueMasterSlaveLeaseTest extends DbRestartJDBCQueueMasterSlaveTest { + private static final transient Logger LOG = LoggerFactory.getLogger(DbRestartJDBCQueueMasterSlaveLeaseTest.class); + + @Override + protected void configureJdbcPersistenceAdapter(JDBCPersistenceAdapter persistenceAdapter) throws IOException { + super.configureJdbcPersistenceAdapter(persistenceAdapter); + persistenceAdapter.setLocker(new LeaseDatabaseLocker()); + persistenceAdapter.getLocker().setLockAcquireSleepInterval(getLockAcquireSleepInterval()); + persistenceAdapter.setLockKeepAlivePeriod(getLockKeepAlivePeriod()); + } + + @Override + protected void configureBroker(BrokerService brokerService) { + //let the brokers die on exception and master should have lease on restart + // which will delay slave start till it expires + LeaseLockerIOExceptionHandler ioExceptionHandler = new LeaseLockerIOExceptionHandler(); + ioExceptionHandler.setIgnoreSQLExceptions(false); + ioExceptionHandler.setStopStartConnectors(false); + ioExceptionHandler.setResumeCheckSleepPeriod(500l); + brokerService.setIoExceptionHandler(ioExceptionHandler); + } + + private long getLockKeepAlivePeriod() { + return 1000; + } + + private long getLockAcquireSleepInterval() { + return 8000; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveTest.java new file mode 100644 index 0000000000..fb04803128 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueMasterSlaveTest.java @@ -0,0 +1,149 @@ +/** + * 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.broker.ft; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TransactionRolledBackException; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbRestartJDBCQueueMasterSlaveTest extends JDBCQueueMasterSlaveTest { + private static final transient Logger LOG = LoggerFactory.getLogger(DbRestartJDBCQueueMasterSlaveTest.class); + + protected void messageSent() throws Exception { + verifyExpectedBroker(inflightMessageCount); + if (++inflightMessageCount == failureCount) { + LOG.info("STOPPING DB!@!!!!"); + final EmbeddedDataSource ds = ((SyncCreateDataSource)getExistingDataSource()).getDelegate(); + ds.setShutdownDatabase("shutdown"); + LOG.info("DB STOPPED!@!!!!"); + + Thread dbRestartThread = new Thread("db-re-start-thread") { + public void run() { + delayTillRestartRequired(); + ds.setShutdownDatabase("false"); + LOG.info("DB RESTARTED!@!!!!"); + } + }; + dbRestartThread.start(); + } + verifyExpectedBroker(inflightMessageCount); + } + + protected void verifyExpectedBroker(int inflightMessageCount) { + if (inflightMessageCount == 0) { + assertEquals("connected to master", master.getBrokerName(), ((ActiveMQConnection)sendConnection).getBrokerName()); + } else if (inflightMessageCount == failureCount + 10) { + assertEquals("connected to slave, count:" + inflightMessageCount, slave.get().getBrokerName(), ((ActiveMQConnection)sendConnection).getBrokerName()); + } + } + + protected void delayTillRestartRequired() { + LOG.info("Waiting for master broker to Stop"); + master.waitUntilStopped(); + } + + protected void sendToProducer(MessageProducer producer, + Destination producerDestination, Message message) throws JMSException { + producer.send(producerDestination, message); + } + + @Override + protected Session createReceiveSession(Connection receiveConnection) throws Exception { + return receiveConnection.createSession(true, Session.SESSION_TRANSACTED); + } + + @Override + protected void consumeMessage(Message message, List messageList) { + try { + receiveSession.commit(); + super.consumeMessage(message, messageList); + } catch (JMSException e) { + LOG.info("Failed to commit message receipt: " + message, e); + try { + receiveSession.rollback(); + } catch (JMSException ignored) { + } + + if (e instanceof TransactionRolledBackException) { + TransactionRolledBackException transactionRolledBackException = (TransactionRolledBackException) e; + if (transactionRolledBackException.getMessage().indexOf("in doubt") != -1) { + // failover chucked bc there is a missing reply to a commit. + // failover is involved b/c the store exception is handled broker side and the client just + // sees a disconnect (socket.close()). + // If the client needs to be aware of the failure then it should not use IOExceptionHandler + // so that the exception will propagate back + + // for this test case: + // the commit may have got there and the reply is lost "or" the commit may be lost. + // so we may or may not get a resend. + // + // At the application level we need to determine if the message is there or not which is not trivial + // for this test we assert received == sent + // so we need to know whether the message will be replayed. + // we can ask the store b/c we know it is jdbc - guess we could go through a destination + // message store interface also or use jmx + java.sql.Connection dbConnection = null; + try { + ActiveMQMessage mqMessage = (ActiveMQMessage) message; + MessageId id = mqMessage.getMessageId(); + dbConnection = sharedDs.getConnection(); + PreparedStatement s = dbConnection.prepareStatement(((JDBCPersistenceAdapter) connectedToBroker().getPersistenceAdapter()).getStatements().getFindMessageStatement()); + s.setString(1, id.getProducerId().toString()); + s.setLong(2, id.getProducerSequenceId()); + ResultSet rs = s.executeQuery(); + + if (!rs.next()) { + // message is gone, so lets count it as consumed + LOG.info("On TransactionRolledBackException we know that the ack/commit got there b/c message is gone so we count it: " + mqMessage); + super.consumeMessage(message, messageList); + } else { + LOG.info("On TransactionRolledBackException we know that the ack/commit was lost so we expect a replay of: " + mqMessage); + } + } catch (Exception dbe) { + dbe.printStackTrace(); + } finally { + try { + dbConnection.close(); + } catch (SQLException e1) { + e1.printStackTrace(); + } + } + } + } + } + } + + private BrokerService connectedToBroker() { + return ((ActiveMQConnection)receiveConnection).getBrokerInfo().getBrokerName().equals("master") ? master : slave.get(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueTest.java new file mode 100644 index 0000000000..9b21c441ea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/DbRestartJDBCQueueTest.java @@ -0,0 +1,158 @@ +/** + * 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.broker.ft; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsTopicSendReceiveWithTwoConnectionsTest; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.jdbc.DataSourceServiceSupport; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.util.DefaultIOExceptionHandler; +import org.apache.activemq.util.IOHelper; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DbRestartJDBCQueueTest extends JmsTopicSendReceiveWithTwoConnectionsTest implements ExceptionListener { + private static final transient Logger LOG = LoggerFactory.getLogger(DbRestartJDBCQueueTest.class); + + public boolean transactedSends = false; + public int failureCount = 25; // or 20 for even tx batch boundary + + int inflightMessageCount = 0; + EmbeddedDataSource sharedDs; + BrokerService broker; + final CountDownLatch restartDBLatch = new CountDownLatch(1); + + protected void setUp() throws Exception { + setAutoFail(true); + topic = false; + verbose = true; + // startup db + sharedDs = (EmbeddedDataSource) DataSourceServiceSupport.createDataSource(IOHelper.getDefaultDataDirectory()); + + broker = new BrokerService(); + + DefaultIOExceptionHandler handler = new DefaultIOExceptionHandler(); + handler.setIgnoreSQLExceptions(false); + handler.setStopStartConnectors(true); + broker.setIoExceptionHandler(handler); + broker.addConnector("tcp://localhost:0"); + broker.setUseJmx(false); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(true); + JDBCPersistenceAdapter persistenceAdapter = new JDBCPersistenceAdapter(); + persistenceAdapter.setDataSource(sharedDs); + persistenceAdapter.setUseLock(false); + persistenceAdapter.setLockKeepAlivePeriod(500); + persistenceAdapter.getLocker().setLockAcquireSleepInterval(500); + broker.setPersistenceAdapter(persistenceAdapter); + broker.start(); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + broker.stop(); + } + + + protected Session createSendSession(Connection sendConnection) throws Exception { + if (transactedSends) { + return sendConnection.createSession(true, Session.SESSION_TRANSACTED); + } else { + return sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory f = + new ActiveMQConnectionFactory("failover://" + broker.getTransportConnectors().get(0).getPublishableConnectString()); + f.setExceptionListener(this); + return f; + } + + @Override + protected void messageSent() throws Exception { + if (++inflightMessageCount == failureCount) { + LOG.info("STOPPING DB!@!!!!"); + final EmbeddedDataSource ds = sharedDs; + ds.setShutdownDatabase("shutdown"); + try { + ds.getConnection(); + } catch (Exception ignored) { + } + LOG.info("DB STOPPED!@!!!!"); + + Thread dbRestartThread = new Thread("db-re-start-thread") { + public void run() { + LOG.info("Sleeping for 10 seconds before allowing db restart"); + try { + restartDBLatch.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + ds.setShutdownDatabase("false"); + LOG.info("DB RESTARTED!@!!!!"); + } + }; + dbRestartThread.start(); + } + } + + protected void sendToProducer(MessageProducer producer, + Destination producerDestination, Message message) throws JMSException { + { + // do some retries as db failures filter back to the client until broker sees + // db lock failure and shuts down + boolean sent = false; + do { + try { + producer.send(producerDestination, message); + + if (transactedSends && ((inflightMessageCount+1) %10 == 0 || (inflightMessageCount+1) >= messageCount)) { + LOG.info("committing on send: " + inflightMessageCount + " message: " + message); + session.commit(); + } + + sent = true; + } catch (JMSException e) { + LOG.info("Exception on producer send:", e); + try { + Thread.sleep(2000); + } catch (InterruptedException ignored) { + } + } + } while(!sent); + + } + } + + @Override + public void onException(JMSException exception) { + LOG.error("exception on connection: ", exception); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/JDBCQueueMasterSlaveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/JDBCQueueMasterSlaveTest.java new file mode 100644 index 0000000000..c7b0ec6980 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/JDBCQueueMasterSlaveTest.java @@ -0,0 +1,112 @@ +/** + * 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.broker.ft; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URI; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +import javax.sql.DataSource; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.store.jdbc.DataSourceServiceSupport; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.util.DefaultIOExceptionHandler; +import org.apache.activemq.util.IOHelper; +import org.apache.derby.jdbc.EmbeddedDataSource; + +public class JDBCQueueMasterSlaveTest extends QueueMasterSlaveTestSupport { + protected DataSource sharedDs; + protected String MASTER_URL = "tcp://localhost:62001"; + protected String SLAVE_URL = "tcp://localhost:62002"; + + protected void setUp() throws Exception { + // startup db + sharedDs = new SyncCreateDataSource((EmbeddedDataSource) DataSourceServiceSupport.createDataSource(IOHelper.getDefaultDataDirectory())); + super.setUp(); + } + + protected void createMaster() throws Exception { + master = new BrokerService(); + master.setBrokerName("master"); + master.addConnector(MASTER_URL); + master.setUseJmx(false); + master.setPersistent(true); + master.setDeleteAllMessagesOnStartup(true); + JDBCPersistenceAdapter persistenceAdapter = new JDBCPersistenceAdapter(); + persistenceAdapter.setDataSource(getExistingDataSource()); + configureJdbcPersistenceAdapter(persistenceAdapter); + master.setPersistenceAdapter(persistenceAdapter); + configureBroker(master); + master.start(); + } + + protected void configureBroker(BrokerService brokerService) { + DefaultIOExceptionHandler stopBrokerOnStoreException = new DefaultIOExceptionHandler(); + // we want any store io exception to stop the broker + stopBrokerOnStoreException.setIgnoreSQLExceptions(false); + brokerService.setIoExceptionHandler(stopBrokerOnStoreException); + } + + protected void createSlave() throws Exception { + // use a separate thread as the slave will block waiting for + // the exclusive db lock + Thread t = new Thread() { + public void run() { + try { + BrokerService broker = new BrokerService(); + broker.setBrokerName("slave"); + TransportConnector connector = new TransportConnector(); + connector.setUri(new URI(SLAVE_URL)); + broker.addConnector(connector); + // no need for broker.setMasterConnectorURI(masterConnectorURI) + // as the db lock provides the slave/master initialisation + broker.setUseJmx(false); + broker.setPersistent(true); + JDBCPersistenceAdapter persistenceAdapter = new JDBCPersistenceAdapter(); + persistenceAdapter.setDataSource(getExistingDataSource()); + persistenceAdapter.setCreateTablesOnStartup(false); + broker.setPersistenceAdapter(persistenceAdapter); + configureJdbcPersistenceAdapter(persistenceAdapter); + configureBroker(broker); + broker.start(); + slave.set(broker); + slaveStarted.countDown(); + } catch (IllegalStateException expectedOnShutdown) { + } catch (Exception e) { + fail("failed to start slave broker, reason:" + e); + } + } + }; + t.start(); + } + + protected void configureJdbcPersistenceAdapter(JDBCPersistenceAdapter persistenceAdapter) throws IOException { + persistenceAdapter.setLockKeepAlivePeriod(500); + persistenceAdapter.getLocker().setLockAcquireSleepInterval(500); + } + + protected DataSource getExistingDataSource() throws Exception { + return sharedDs; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveSingleUrlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveSingleUrlTest.java new file mode 100644 index 0000000000..7dc88f753b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveSingleUrlTest.java @@ -0,0 +1,95 @@ +/** + * 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.broker.ft; + +import java.io.File; +import java.net.URI; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.leveldb.LevelDBStore; +import org.junit.Ignore; + + +public class QueueMasterSlaveSingleUrlTest extends QueueMasterSlaveTestSupport { + private final String brokerUrl = "tcp://localhost:62001"; + private final String singleUriString = "failover://(" + brokerUrl +")?randomize=false"; + + @Override + protected void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(singleUriString); + } + + @Override + protected void createMaster() throws Exception { + master = new BrokerService(); + master.setBrokerName("shared-master"); + configureSharedPersistenceAdapter(master); + master.addConnector(brokerUrl); + master.start(); + } + + private void configureSharedPersistenceAdapter(BrokerService broker) throws Exception { + LevelDBStore adapter = new LevelDBStore(); + adapter.setDirectory(new File("shared")); + broker.setPersistenceAdapter(adapter); + } + + @Override + protected void createSlave() throws Exception { + new Thread(new Runnable() { + @Override + public void run() { + try { + BrokerService broker = new BrokerService(); + broker.setBrokerName("shared-slave"); + configureSharedPersistenceAdapter(broker); + // add transport as a service so that it is bound on start, after store started + final TransportConnector tConnector = new TransportConnector(); + tConnector.setUri(new URI(brokerUrl)); + broker.addConnector(tConnector); + + broker.start(); + slave.set(broker); + slaveStarted.countDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + }).start(); + } + + + // The @Ignore is just here for documentation, since this is a JUnit3 test + // I added the sleep because without it the two other test cases fail. I haven't looked into it, but + // my guess whatever setUp does isn't really finished when the teardown runs. + @Ignore("See https://issues.apache.org/jira/browse/AMQ-5164") + @Override + public void testAdvisory() throws Exception { + Thread.sleep(5 * 1000); + //super.testAdvisory(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveTestSupport.java new file mode 100644 index 0000000000..2808ebe143 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveTestSupport.java @@ -0,0 +1,156 @@ +/** + * 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.broker.ft; + +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsTopicSendReceiveWithTwoConnectionsTest; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * Test failover for Queues + */ +abstract public class QueueMasterSlaveTestSupport extends JmsTopicSendReceiveWithTwoConnectionsTest { + private static final transient Logger LOG = LoggerFactory.getLogger(QueueMasterSlaveTestSupport.class); + + protected BrokerService master; + protected AtomicReference slave = new AtomicReference(); + protected CountDownLatch slaveStarted = new CountDownLatch(1); + protected int inflightMessageCount; + protected int failureCount = 50; + protected String uriString = "failover://(tcp://localhost:62001,tcp://localhost:62002)?randomize=false&useExponentialBackOff=false"; + + @Override + protected void setUp() throws Exception { + setMaxTestTime(TimeUnit.MINUTES.toMillis(10)); + setAutoFail(true); + if (System.getProperty("basedir") == null) { + File file = new File("."); + System.setProperty("basedir", file.getAbsolutePath()); + } + super.messageCount = 500; + failureCount = super.messageCount / 2; + super.topic = isTopic(); + createMaster(); + createSlave(); + // wait for thing to connect + Thread.sleep(1000); + super.setUp(); + } + + protected String getSlaveXml() { + return "org/apache/activemq/broker/ft/slave.xml"; + } + + protected String getMasterXml() { + return "org/apache/activemq/broker/ft/master.xml"; + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + master.stop(); + master.waitUntilStopped(); + slaveStarted.await(60, TimeUnit.SECONDS); + BrokerService brokerService = slave.get(); + if( brokerService!=null ) { + brokerService.stop(); + } + master.stop(); + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(uriString); + } + + @Override + protected void messageSent() throws Exception { + if (++inflightMessageCount == failureCount) { + Thread.sleep(1000); + LOG.error("MASTER STOPPED!@!!!!"); + master.stop(); + } + } + + protected boolean isTopic() { + return false; + } + + protected void createMaster() throws Exception { + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(new ClassPathResource(getMasterXml())); + brokerFactory.afterPropertiesSet(); + master = brokerFactory.getBroker(); + master.start(); + } + + protected void createSlave() throws Exception { + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(new ClassPathResource(getSlaveXml())); + brokerFactory.afterPropertiesSet(); + BrokerService broker = brokerFactory.getBroker(); + broker.start(); + slave.set(broker); + slaveStarted.countDown(); + } + + public void testVirtualTopicFailover() throws Exception { + + MessageConsumer qConsumer = session.createConsumer(new ActiveMQQueue("Consumer.A.VirtualTopic.TA1")); + assertNull("No message there yet", qConsumer.receive(1000)); + qConsumer.close(); + assertTrue(!master.isSlave()); + master.stop(); + assertTrue("slave started", slaveStarted.await(60, TimeUnit.SECONDS)); + assertTrue(!slave.get().isSlave()); + + final String text = "ForUWhenSlaveKicksIn"; + producer.send(new ActiveMQTopic("VirtualTopic.TA1"), session.createTextMessage(text)); + + qConsumer = session.createConsumer(new ActiveMQQueue("Consumer.A.VirtualTopic.TA1")); + + javax.jms.Message message = qConsumer.receive(4000); + assertNotNull("Get message after failover", message); + assertEquals("correct message", text, ((TextMessage)message).getText()); + } + + public void testAdvisory() throws Exception { + MessageConsumer advConsumer = session.createConsumer(AdvisorySupport.getMasterBrokerAdvisoryTopic()); + + master.stop(); + assertTrue("slave started", slaveStarted.await(60, TimeUnit.SECONDS)); + LOG.info("slave started"); + Message advisoryMessage = advConsumer.receive(5000); + LOG.info("received " + advisoryMessage); + assertNotNull("Didn't received advisory", advisoryMessage); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveTestUsingSharedFileTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveTestUsingSharedFileTest.java new file mode 100644 index 0000000000..c9f178dd47 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/QueueMasterSlaveTestUsingSharedFileTest.java @@ -0,0 +1,44 @@ +/** + * 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.broker.ft; + +public class QueueMasterSlaveTestUsingSharedFileTest extends + QueueMasterSlaveTestSupport { + + protected String getSlaveXml() { + return "org/apache/activemq/broker/ft/sharedFileSlave.xml"; + } + + protected String getMasterXml() { + return "org/apache/activemq/broker/ft/sharedFileMaster.xml"; + } + + protected void createSlave() throws Exception { + // Start the Brokers async since starting them up could be a blocking operation.. + new Thread(new Runnable() { + public void run() { + try { + QueueMasterSlaveTestUsingSharedFileTest.super.createSlave(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + }).start(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/SyncCreateDataSource.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/SyncCreateDataSource.java new file mode 100644 index 0000000000..5331a226a6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/SyncCreateDataSource.java @@ -0,0 +1,86 @@ +/** + * 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.broker.ft; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; +import javax.sql.DataSource; +import org.apache.derby.jdbc.EmbeddedDataSource; + +// prevent concurrent calls from attempting to create the db at the same time +// can result in "already exists in this jvm" errors + +public class SyncCreateDataSource implements DataSource { + final EmbeddedDataSource delegate; + + SyncCreateDataSource(EmbeddedDataSource dataSource) { + this.delegate = dataSource; + } + + @Override + public Connection getConnection() throws SQLException { + synchronized (this) { + return delegate.getConnection(); + } + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + synchronized (this) { + return delegate.getConnection(); + } + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + EmbeddedDataSource getDelegate() { + return delegate; + } + + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/kahaDbJdbcLeaseQueueMasterSlaveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/kahaDbJdbcLeaseQueueMasterSlaveTest.java new file mode 100644 index 0000000000..ee7ca0f8c8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/kahaDbJdbcLeaseQueueMasterSlaveTest.java @@ -0,0 +1,114 @@ +/** + * 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.broker.ft; + +import java.io.IOException; +import java.net.URI; +import javax.sql.DataSource; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.store.jdbc.DataSourceServiceSupport; +import org.apache.activemq.store.jdbc.LeaseDatabaseLocker; +import org.apache.activemq.store.jdbc.Statements; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.DefaultIOExceptionHandler; +import org.apache.activemq.util.IOHelper; +import org.apache.derby.jdbc.EmbeddedDataSource; + +public class kahaDbJdbcLeaseQueueMasterSlaveTest extends QueueMasterSlaveTestSupport { + protected DataSource sharedDs; + protected String MASTER_URL = "tcp://localhost:62001"; + protected String SLAVE_URL = "tcp://localhost:62002"; + + protected void setUp() throws Exception { + // startup db + sharedDs = new SyncCreateDataSource((EmbeddedDataSource) DataSourceServiceSupport.createDataSource(IOHelper.getDefaultDataDirectory())); + super.setUp(); + } + + protected void createMaster() throws Exception { + master = new BrokerService(); + master.setBrokerName("master"); + master.addConnector(MASTER_URL); + master.setUseJmx(false); + master.setPersistent(true); + master.setDeleteAllMessagesOnStartup(true); + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter) master.getPersistenceAdapter(); + LeaseDatabaseLocker leaseDatabaseLocker = new LeaseDatabaseLocker(); + leaseDatabaseLocker.setCreateTablesOnStartup(true); + leaseDatabaseLocker.setDataSource(getExistingDataSource()); + leaseDatabaseLocker.setStatements(new Statements()); + kahaDBPersistenceAdapter.setLocker(leaseDatabaseLocker); + configureLocker(kahaDBPersistenceAdapter); + configureBroker(master); + master.start(); + } + + protected void configureBroker(BrokerService brokerService) { + DefaultIOExceptionHandler stopBrokerOnStoreException = new DefaultIOExceptionHandler(); + // we want any store io exception to stop the broker + stopBrokerOnStoreException.setIgnoreSQLExceptions(false); + brokerService.setIoExceptionHandler(stopBrokerOnStoreException); + } + + protected void createSlave() throws Exception { + // use a separate thread as the slave will block waiting for + // the exclusive db lock + Thread t = new Thread() { + public void run() { + try { + BrokerService broker = new BrokerService(); + broker.setBrokerName("slave"); + TransportConnector connector = new TransportConnector(); + connector.setUri(new URI(SLAVE_URL)); + broker.addConnector(connector); + broker.setUseJmx(false); + broker.setPersistent(true); + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + LeaseDatabaseLocker leaseDatabaseLocker = new LeaseDatabaseLocker(); + leaseDatabaseLocker.setDataSource(getExistingDataSource()); + leaseDatabaseLocker.setStatements(new Statements()); + kahaDBPersistenceAdapter.setLocker(leaseDatabaseLocker); + configureLocker(kahaDBPersistenceAdapter); + configureBroker(broker); + broker.start(); + slave.set(broker); + slaveStarted.countDown(); + } catch (IllegalStateException expectedOnShutdown) { + } catch (Exception e) { + fail("failed to start slave broker, reason:" + e); + } + } + }; + t.start(); + } + + protected void configureLocker(KahaDBPersistenceAdapter kahaDBPersistenceAdapter) throws IOException { + kahaDBPersistenceAdapter.setLockKeepAlivePeriod(500); + kahaDBPersistenceAdapter.getLocker().setLockAcquireSleepInterval(500); + } + + @Override + public void testVirtualTopicFailover() throws Exception { + // Ignoring for now, see AMQ-4842 + } + + protected DataSource getExistingDataSource() throws Exception { + return sharedDs; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/mKahaDbQueueMasterSlaveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/mKahaDbQueueMasterSlaveTest.java new file mode 100644 index 0000000000..ad9cca1ba0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/mKahaDbQueueMasterSlaveTest.java @@ -0,0 +1,89 @@ +/** + * 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.broker.ft; + +import java.net.URI; +import java.util.LinkedList; +import java.util.List; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; + +public class mKahaDbQueueMasterSlaveTest extends QueueMasterSlaveTestSupport { + protected String MASTER_URL = "tcp://localhost:62001"; + protected String SLAVE_URL = "tcp://localhost:62002"; + + protected void createMaster() throws Exception { + master = new BrokerService(); + master.setBrokerName("master"); + master.addConnector(MASTER_URL); + master.setUseJmx(false); + master.setPersistent(true); + master.setDeleteAllMessagesOnStartup(true); + + MultiKahaDBPersistenceAdapter mKahaDB = new MultiKahaDBPersistenceAdapter(); + List adapters = new LinkedList(); + FilteredKahaDBPersistenceAdapter defaultEntry = new FilteredKahaDBPersistenceAdapter(); + defaultEntry.setPersistenceAdapter(new KahaDBPersistenceAdapter()); + defaultEntry.setPerDestination(true); + adapters.add(defaultEntry); + + mKahaDB.setFilteredPersistenceAdapters(adapters); + master.setPersistenceAdapter(mKahaDB); + + master.start(); + } + + protected void createSlave() throws Exception { + // use a separate thread as the slave will block waiting for + // the exclusive db lock + Thread t = new Thread() { + public void run() { + try { + BrokerService broker = new BrokerService(); + broker.setBrokerName("slave"); + TransportConnector connector = new TransportConnector(); + connector.setUri(new URI(SLAVE_URL)); + broker.addConnector(connector); + // no need for broker.setMasterConnectorURI(masterConnectorURI) + // as the db lock provides the slave/master initialisation + broker.setUseJmx(false); + broker.setPersistent(true); + + MultiKahaDBPersistenceAdapter mKahaDB = new MultiKahaDBPersistenceAdapter(); + List adapters = new LinkedList(); + FilteredKahaDBPersistenceAdapter defaultEntry = new FilteredKahaDBPersistenceAdapter(); + defaultEntry.setPersistenceAdapter(new KahaDBPersistenceAdapter()); + defaultEntry.setPerDestination(true); + adapters.add(defaultEntry); + + mKahaDB.setFilteredPersistenceAdapters(adapters); + broker.setPersistenceAdapter(mKahaDB); + broker.start(); + slave.set(broker); + slaveStarted.countDown(); + } catch (IllegalStateException expectedOnShutdown) { + } catch (Exception e) { + fail("failed to start slave broker, reason:" + e); + } + } + }; + t.start(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/sharedFileMaster.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/sharedFileMaster.xml new file mode 100644 index 0000000000..f5eef67da2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/sharedFileMaster.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/sharedFileSlave.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/sharedFileSlave.xml new file mode 100644 index 0000000000..7c88a8c689 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/ft/sharedFileSlave.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/BrokerViewSlowStoreStartupTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/BrokerViewSlowStoreStartupTest.java new file mode 100644 index 0000000000..6910bed277 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/BrokerViewSlowStoreStartupTest.java @@ -0,0 +1,356 @@ +/** + * 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.broker.jmx; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.NoSuchElementException; +import java.util.concurrent.CountDownLatch; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Used to verify that the BrokerView accessed while the BrokerSerivce is waiting + * for a Slow Store startup to complete doesn't throw unexpected NullPointerExceptions. + */ +public class BrokerViewSlowStoreStartupTest { + + private static final Logger LOG = LoggerFactory.getLogger(BrokerViewSlowStoreStartupTest.class); + + private final CountDownLatch holdStoreStart = new CountDownLatch(1); + private final String brokerName = "brokerViewTest"; + + private BrokerService broker; + private Thread startThread; + + private BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName(brokerName); + + KahaDBStore kaha = new KahaDBStore() { + + @Override + public void start() throws Exception { + LOG.info("Test KahaDB class is waiting for signal to complete its start()"); + holdStoreStart.await(); + super.start(); + LOG.info("Test KahaDB class is completed its start()"); + } + }; + + kaha.setDirectory(new File("target/activemq-data/kahadb")); + kaha.deleteAllMessages(); + + broker.setPersistenceAdapter(kaha); + broker.setUseJmx(true); + + return broker; + } + + @Before + public void setUp() throws Exception { + broker = createBroker(); + + startThread = new Thread(new Runnable() { + + @Override + public void run() { + try { + broker.start(); + } catch(Exception e) { + e.printStackTrace(); + } + } + }); + startThread.start(); + } + + @After + public void tearDown() throws Exception { + + // ensure we don't keep the broker held if an exception occurs somewhere. + holdStoreStart.countDown(); + + startThread.join(); + + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test(timeout=120000) + public void testBrokerViewOnSlowStoreStart() throws Exception { + + // Ensure we have an Admin View. + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return (broker.getAdminView()) != null; + } + })); + + final BrokerView view = broker.getAdminView(); + + try { + view.getBrokerName(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getBrokerId(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTotalEnqueueCount(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTotalDequeueCount(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTotalConsumerCount(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTotalProducerCount(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTotalMessageCount(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTotalMessagesCached(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.resetStatistics(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.enableStatistics(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.disableStatistics(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.isStatisticsEnabled(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTopics(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getQueues(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTemporaryTopics(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTemporaryQueues(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTopicSubscribers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getDurableTopicSubscribers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getQueueSubscribers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTemporaryTopicSubscribers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTemporaryQueueSubscribers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getInactiveDurableTopicSubscribers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTopicProducers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getQueueProducers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTemporaryTopicProducers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getTemporaryQueueProducers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.getDynamicDestinationProducers(); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.removeConnector("tcp"); + fail("Should have thrown an NoSuchElementException"); + } catch(NoSuchElementException e) { + } + + try { + view.removeNetworkConnector("tcp"); + fail("Should have thrown an NoSuchElementException"); + } catch(NoSuchElementException e) { + } + + try { + view.addTopic("TEST"); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.addQueue("TEST"); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.removeTopic("TEST"); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.removeQueue("TEST"); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.createDurableSubscriber("1", "2", "3","4"); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + try { + view.destroyDurableSubscriber("1", "2"); + fail("Should have thrown an IllegalStateException"); + } catch(IllegalStateException e) { + } + + holdStoreStart.countDown(); + startThread.join(); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return view.getBroker() != null; + } + }); + assertNotNull(view.getBroker()); + + try { + view.getBrokerName(); + } catch(Exception e) { + fail("caught an exception getting the Broker property: " + e.getClass().getName()); + } + + try { + view.getBrokerId(); + } catch(IllegalStateException e) { + fail("caught an exception getting the Broker property: " + e.getClass().getName()); + } + + try { + view.getTotalEnqueueCount(); + } catch(IllegalStateException e) { + fail("caught an exception getting the Broker property: " + e.getClass().getName()); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/HealthViewMBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/HealthViewMBeanTest.java new file mode 100644 index 0000000000..9998be975e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/HealthViewMBeanTest.java @@ -0,0 +1,117 @@ +/** + * 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.broker.jmx; + +import java.util.List; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.MBeanServer; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HealthViewMBeanTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(MBeanTest.class); + protected MBeanServer mbeanServer; + protected String domain = "org.apache.activemq"; + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + useTopic = false; + super.setUp(); + mbeanServer = broker.getManagementContext().getMBeanServer(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString()); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(true); + answer.setDeleteAllMessagesOnStartup(true); + answer.getSystemUsage().getMemoryUsage().setLimit(1024 * 1024 * 64); + answer.getSystemUsage().getTempUsage().setLimit(1024 * 1024 * 64); + answer.getSystemUsage().getStoreUsage().setLimit(1024 * 1024 * 64); + answer.setUseJmx(true); + answer.setSchedulerSupport(true); + + // allow options to be visible via jmx + + answer.addConnector(bindAddress); + return answer; + } + + public void testHealthView() throws Exception{ + Connection connection = connectionFactory.createConnection(); + + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + for (int i = 0; i < 60; i++) { + BytesMessage message = session.createBytesMessage(); + message.writeBytes(new byte[1024 *1024]); + producer.send(message); + } + + Thread.sleep(1000); + + String objectNameStr = broker.getBrokerObjectName().toString(); + objectNameStr += ",service=Health"; + ObjectName brokerName = assertRegisteredObjectName(objectNameStr); + HealthViewMBean health = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, HealthViewMBean.class, true); + List list = health.healthList(); + + for (HealthStatus status : list) { + LOG.info("Health status: {}", status); + } + + assertEquals(2, list.size()); + } + + protected ObjectName assertRegisteredObjectName(String name) throws MalformedObjectNameException, NullPointerException { + ObjectName objectName = new ObjectName(name); + if (mbeanServer.isRegistered(objectName)) { + LOG.info("Bean Registered: " + objectName); + } else { + fail("Could not find MBean!: " + objectName); + } + return objectName; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/Log4JConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/Log4JConfigTest.java new file mode 100644 index 0000000000..2c2b3735cd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/Log4JConfigTest.java @@ -0,0 +1,200 @@ +/** + * 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.broker.jmx; + +import java.util.List; + +import javax.jms.ConnectionFactory; +import javax.management.MBeanServer; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.Test; +import org.slf4j.LoggerFactory; + +public class Log4JConfigTest extends EmbeddedBrokerTestSupport { + + private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(Log4JConfigTest.class); + + private static final String BROKER_LOGGER = "org.apache.activemq.broker.BrokerService"; + + protected MBeanServer mbeanServer; + protected String domain = "org.apache.activemq"; + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + useTopic = false; + super.setUp(); + mbeanServer = broker.getManagementContext().getMBeanServer(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString()); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(true); + answer.setDeleteAllMessagesOnStartup(true); + answer.setUseJmx(true); + answer.setSchedulerSupport(true); + answer.addConnector(bindAddress); + return answer; + } + + @Test + public void testLog4JConfigViewExists() throws Exception { + String brokerObjectName = broker.getBrokerObjectName().toString(); + String log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName).toString(); + assertRegisteredObjectName(log4jConfigViewName); + } + + @Test + public void testLog4JConfigViewGetLoggers() throws Throwable { + String brokerObjectName = broker.getBrokerObjectName().toString(); + ObjectName log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName); + Log4JConfigViewMBean log4jConfigView = MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, log4jConfigViewName, Log4JConfigViewMBean.class, true); + + List loggers = log4jConfigView.getLoggers(); + assertNotNull(loggers); + assertFalse(loggers.isEmpty()); + } + + @Test + public void testLog4JConfigViewGetLevel() throws Throwable { + String brokerObjectName = broker.getBrokerObjectName().toString(); + ObjectName log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName); + Log4JConfigViewMBean log4jConfigView = MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, log4jConfigViewName, Log4JConfigViewMBean.class, true); + + String level = log4jConfigView.getLogLevel(BROKER_LOGGER); + assertNotNull(level); + assertFalse(level.isEmpty()); + } + + @Test + public void testLog4JConfigViewGetLevelUnknownLoggerName() throws Throwable { + String brokerObjectName = broker.getBrokerObjectName().toString(); + ObjectName log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName); + Log4JConfigViewMBean log4jConfigView = MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, log4jConfigViewName, Log4JConfigViewMBean.class, true); + + // Non-existent loggers will return a name equal to the root level. + String level = log4jConfigView.getLogLevel("not.a.logger"); + assertNotNull(level); + assertFalse(level.isEmpty()); + assertEquals(Logger.getRootLogger().getLevel().toString(), level); + } + + @Test + public void testLog4JConfigViewSetLevel() throws Throwable { + String brokerObjectName = broker.getBrokerObjectName().toString(); + ObjectName log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName); + Log4JConfigViewMBean log4jConfigView = MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, log4jConfigViewName, Log4JConfigViewMBean.class, true); + + String level = log4jConfigView.getLogLevel(BROKER_LOGGER); + assertNotNull(level); + assertFalse(level.isEmpty()); + + log4jConfigView.setLogLevel(BROKER_LOGGER, "WARN"); + level = log4jConfigView.getLogLevel(BROKER_LOGGER); + assertNotNull(level); + assertEquals("WARN", level); + + log4jConfigView.setLogLevel(BROKER_LOGGER, "INFO"); + level = log4jConfigView.getLogLevel(BROKER_LOGGER); + assertNotNull(level); + assertEquals("INFO", level); + } + + @Test + public void testLog4JConfigViewSetLevelNoChangeIfLevelIsBad() throws Throwable { + String brokerObjectName = broker.getBrokerObjectName().toString(); + ObjectName log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName); + Log4JConfigViewMBean log4jConfigView = MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, log4jConfigViewName, Log4JConfigViewMBean.class, true); + + log4jConfigView.setLogLevel(BROKER_LOGGER, "INFO"); + String level = log4jConfigView.getLogLevel(BROKER_LOGGER); + assertNotNull(level); + assertEquals("INFO", level); + + log4jConfigView.setLogLevel(BROKER_LOGGER, "BAD"); + level = log4jConfigView.getLogLevel(BROKER_LOGGER); + assertNotNull(level); + assertEquals("INFO", level); + } + + @Test + public void testLog4JConfigViewGetRootLogLevel() throws Throwable { + String brokerObjectName = broker.getBrokerObjectName().toString(); + ObjectName log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName); + Log4JConfigViewMBean log4jConfigView = MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, log4jConfigViewName, Log4JConfigViewMBean.class, true); + + String level = log4jConfigView.getRootLogLevel(); + assertNotNull(level); + assertFalse(level.isEmpty()); + + String currentRootLevel = Logger.getRootLogger().getLevel().toString(); + assertEquals(currentRootLevel, level); + } + + @Test + public void testLog4JConfigViewSetRootLevel() throws Throwable { + String brokerObjectName = broker.getBrokerObjectName().toString(); + ObjectName log4jConfigViewName = BrokerMBeanSupport.createLog4JConfigViewName(brokerObjectName); + Log4JConfigViewMBean log4jConfigView = MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, log4jConfigViewName, Log4JConfigViewMBean.class, true); + + String currentRootLevel = Logger.getRootLogger().getLevel().toString(); + log4jConfigView.setRootLogLevel("WARN"); + currentRootLevel = Logger.getRootLogger().getLevel().toString(); + assertEquals("WARN", currentRootLevel); + log4jConfigView.setRootLogLevel("INFO"); + currentRootLevel = Logger.getRootLogger().getLevel().toString(); + assertEquals("INFO", currentRootLevel); + + Level level; + } + + protected ObjectName assertRegisteredObjectName(String name) throws MalformedObjectNameException, NullPointerException { + ObjectName objectName = new ObjectName(name); + if (mbeanServer.isRegistered(objectName)) { + LOG.info("Bean Registered: " + objectName); + } else { + fail("Could not find MBean!: " + objectName); + } + return objectName; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanOperationTimeoutTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanOperationTimeoutTest.java new file mode 100644 index 0000000000..b7c00b8a62 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanOperationTimeoutTest.java @@ -0,0 +1,131 @@ +/** + * 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.broker.jmx; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.MBeanServer; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class MBeanOperationTimeoutTest { + private static final Logger LOG = LoggerFactory.getLogger(MBeanOperationTimeoutTest.class); + + private ActiveMQConnectionFactory connectionFactory; + private BrokerService broker; + private String connectionUri; + private static final String destinationName = "MBeanOperationTimeoutTestQ"; + private static final String moveToDestinationName = "MBeanOperationTimeoutTestQ.Moved"; + + protected MBeanServer mbeanServer; + protected String domain = "org.apache.activemq"; + + protected int messageCount = 50000; + + @Test(expected = TimeoutException.class) + public void testLongOperationTimesOut() throws Exception { + + sendMessages(messageCount); + LOG.info("Produced " + messageCount + " messages to the broker."); + + // Now get the QueueViewMBean and purge + String objectNameStr = broker.getBrokerObjectName().toString(); + objectNameStr += ",destinationType=Queue,destinationName="+destinationName; + + ObjectName queueViewMBeanName = assertRegisteredObjectName(objectNameStr); + QueueViewMBean proxy = (QueueViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + long count = proxy.getQueueSize(); + assertEquals("Queue size", count, messageCount); + + LOG.info("Attempting to move one message, TimeoutException expected"); + proxy.moveMatchingMessagesTo(null, moveToDestinationName); + } + + private void sendMessages(int count) throws Exception { + Connection connection = connectionFactory.createConnection(); + try { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(destinationName); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < messageCount; i++) { + Message message = session.createMessage(); + message.setIntProperty("id", i); + producer.send(message); + } + session.commit(); + } finally { + connection.close(); + } + } + + protected ObjectName assertRegisteredObjectName(String name) throws MalformedObjectNameException, NullPointerException { + ObjectName objectName = new ObjectName(name); + if (mbeanServer.isRegistered(objectName)) { + LOG.info("Bean Registered: " + objectName); + } else { + fail("Could not find MBean!: " + objectName); + } + return objectName; + } + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + mbeanServer = broker.getManagementContext().getMBeanServer(); + } + + @After + public void tearDown() throws Exception { + Thread.sleep(500); + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setMbeanInvocationTimeout(TimeUnit.SECONDS.toMillis(1)); + answer.setUseJmx(true); + answer.addConnector("vm://localhost"); + answer.setDeleteAllMessagesOnStartup(true); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java new file mode 100644 index 0000000000..e2b0c51696 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java @@ -0,0 +1,1508 @@ +/** + * 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.broker.jmx; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; +import javax.management.MBeanServer; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +import junit.textui.TestRunner; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.BlobMessage; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.BaseDestination; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTempQueue; +import org.apache.activemq.util.JMXSupport; +import org.apache.activemq.util.URISupport; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A test case of the various MBeans in ActiveMQ. If you want to look at the + * various MBeans after the test has been run then run this test case as a + * command line application. + */ +public class MBeanTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(MBeanTest.class); + + private static boolean waitForKeyPress; + + protected MBeanServer mbeanServer; + protected String domain = "org.apache.activemq"; + protected String clientID = "foo"; + + protected Connection connection; + protected boolean transacted; + protected int authMode = Session.AUTO_ACKNOWLEDGE; + protected static final int MESSAGE_COUNT = 2*BaseDestination.MAX_PAGE_SIZE; + final static String QUEUE_WITH_OPTIONS = "QueueWithOptions"; + + /** + * When you run this test case from the command line it will pause before + * terminating so that you can look at the MBeans state for debugging + * purposes. + */ + public static void main(String[] args) { + waitForKeyPress = true; + TestRunner.run(MBeanTest.class); + } + + public void testConnectors() throws Exception{ + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + assertEquals("openwire URL port doesn't equal bind Address", + new URI(broker.getTransportConnectorByType("tcp")).getPort(), + new URI(this.broker.getTransportConnectors().get(0).getPublishableConnectString()).getPort()); + } + + public void testMBeans() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + + // test all the various MBeans now we have a producer, consumer and + // messages on a queue + assertSendViaMBean(); + assertSendCsnvViaMBean(); + assertQueueBrowseWorks(); + assertCreateAndDestroyDurableSubscriptions(); + assertConsumerCounts(); + assertProducerCounts(); + } + + public void testMoveMessages() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + CompositeData[] compdatalist = queue.browse(); + int initialQueueSize = compdatalist.length; + if (initialQueueSize == 0) { + fail("There is no message in the queue:"); + } + else { + echo("Current queue size: " + initialQueueSize); + } + int messageCount = initialQueueSize; + String[] messageIDs = new String[messageCount]; + for (int i = 0; i < messageCount; i++) { + CompositeData cdata = compdatalist[i]; + String messageID = (String) cdata.get("JMSMessageID"); + assertNotNull("Should have a message ID for message " + i, messageID); + messageIDs[i] = messageID; + } + + assertTrue("dest has some memory usage", queue.getMemoryPercentUsage() > 0); + + echo("About to move " + messageCount + " messages"); + + String newDestination = getSecondDestinationString(); + for (String messageID : messageIDs) { + //echo("Moving message: " + messageID); + queue.moveMessageTo(messageID, newDestination); + } + + echo("Now browsing the queue"); + compdatalist = queue.browse(); + int actualCount = compdatalist.length; + echo("Current queue size: " + actualCount); + assertEquals("Should now have empty queue but was", initialQueueSize - messageCount, actualCount); + + echo("Now browsing the second queue"); + + queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + newDestination ); + QueueViewMBean queueNew = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + long newQueuesize = queueNew.getQueueSize(); + echo("Second queue size: " + newQueuesize); + assertEquals("Unexpected number of messages ",messageCount, newQueuesize); + + // check memory usage migration + assertTrue("new dest has some memory usage", queueNew.getMemoryPercentUsage() > 0); + assertEquals("old dest has no memory usage", 0, queue.getMemoryPercentUsage()); + assertTrue("use cache", queueNew.isUseCache()); + assertTrue("cache enabled", queueNew.isCacheEnabled()); + assertEquals("no forwards", 0, queueNew.getForwardCount()); + } + + public void testRemoveMessages() throws Exception { + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + broker.addQueue(getDestinationString()); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + String msg1 = queue.sendTextMessage("message 1"); + String msg2 = queue.sendTextMessage("message 2"); + + assertTrue(queue.removeMessage(msg2)); + + connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQDestination dest = createDestination(); + + MessageConsumer consumer = session.createConsumer(dest); + Message message = consumer.receive(1000); + assertNotNull(message); + assertEquals(msg1, message.getJMSMessageID()); + + String msg3 = queue.sendTextMessage("message 3"); + message = consumer.receive(1000); + assertNotNull(message); + assertEquals(msg3, message.getJMSMessageID()); + + message = consumer.receive(1000); + assertNull(message); + + } + + public void testRemoveQueue() throws Exception { + String queueName = "TEST"; + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + broker.addQueue(queueName); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queueName); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + queue.sendTextMessage("message 1"); + queue.sendTextMessage("message 2"); + + assertEquals(2, broker.getTotalMessageCount()); + + broker.removeQueue(queueName); + + assertEquals(0, broker.getTotalMessageCount()); + + } + + public void testRetryMessages() throws Exception { + // lets speed up redelivery + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory) connectionFactory; + factory.getRedeliveryPolicy().setCollisionAvoidancePercent((short) 0); + factory.getRedeliveryPolicy().setMaximumRedeliveries(1); + factory.getRedeliveryPolicy().setInitialRedeliveryDelay(0); + factory.getRedeliveryPolicy().setUseCollisionAvoidance(false); + factory.getRedeliveryPolicy().setUseExponentialBackOff(false); + factory.getRedeliveryPolicy().setBackOffMultiplier((short) 0); + + connection = connectionFactory.createConnection(); + useConnection(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + long initialQueueSize = queue.getQueueSize(); + echo("current queue size: " + initialQueueSize); + assertTrue("dest has some memory usage", queue.getMemoryPercentUsage() > 0); + + // lets create a duff consumer which keeps rolling back... + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(new ActiveMQQueue(getDestinationString())); + Message message = consumer.receive(5000); + while (message != null) { + echo("Message: " + message.getJMSMessageID() + " redelivered " + message.getJMSRedelivered() + " counter " + message.getObjectProperty("JMSXDeliveryCount")); + session.rollback(); + message = consumer.receive(2000); + } + consumer.close(); + session.close(); + + // now lets get the dead letter queue + Thread.sleep(1000); + + 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); + + long initialDlqSize = dlq.getQueueSize(); + CompositeData[] compdatalist = dlq.browse(); + int dlqQueueSize = compdatalist.length; + if (dlqQueueSize == 0) { + fail("There are no messages in the queue:"); + } + else { + echo("Current DLQ queue size: " + dlqQueueSize); + } + int messageCount = dlqQueueSize; + String[] messageIDs = new String[messageCount]; + for (int i = 0; i < messageCount; i++) { + CompositeData cdata = compdatalist[i]; + String messageID = (String) cdata.get("JMSMessageID"); + assertNotNull("Should have a message ID for message " + i, messageID); + messageIDs[i] = messageID; + } + + int dlqMemUsage = dlq.getMemoryPercentUsage(); + assertTrue("dlq has some memory usage", dlqMemUsage > 0); + assertEquals("dest has no memory usage", 0, queue.getMemoryPercentUsage()); + + echo("About to retry " + messageCount + " messages"); + + for (String messageID : messageIDs) { + echo("Retrying message: " + messageID); + dlq.retryMessage(messageID); + } + + long queueSize = queue.getQueueSize(); + compdatalist = queue.browse(); + int actualCount = compdatalist.length; + echo("Orginal queue size is now " + queueSize); + echo("Original browse queue size: " + actualCount); + + long dlqSize = dlq.getQueueSize(); + echo("DLQ size: " + dlqSize); + + assertEquals("DLQ size", initialDlqSize - messageCount, dlqSize); + assertEquals("queue size", initialQueueSize, queueSize); + assertEquals("browse queue size", initialQueueSize, actualCount); + + assertEquals("dest has some memory usage", dlqMemUsage, queue.getMemoryPercentUsage()); + } + + public void testMoveMessagesBySelector() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString() ); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + String newDestination = getSecondDestinationString(); + queue.moveMatchingMessagesTo("counter > 2", newDestination); + + queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + newDestination); + + queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + int movedSize = MESSAGE_COUNT-3; + assertEquals("Unexpected number of messages ",movedSize,queue.getQueueSize()); + + // now lets remove them by selector + queue.removeMatchingMessages("counter > 2"); + + assertEquals("Should have no more messages in the queue: " + queueViewMBeanName, 0, queue.getQueueSize()); + assertEquals("dest has no memory usage", 0, queue.getMemoryPercentUsage()); + } + + public void testCopyMessagesBySelector() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + String newDestination = getSecondDestinationString(); + long queueSize = queue.getQueueSize(); + assertTrue(queueSize > 0); + queue.copyMatchingMessagesTo("counter > 2", newDestination); + + queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + newDestination); + + queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + LOG.info("Queue: " + queueViewMBeanName + " now has: " + queue.getQueueSize() + " message(s)"); + assertEquals("Expected messages in a queue: " + queueViewMBeanName, MESSAGE_COUNT-3, queue.getQueueSize()); + // now lets remove them by selector + queue.removeMatchingMessages("counter > 2"); + + assertEquals("Should have no more messages in the queue: " + queueViewMBeanName, 0, queue.getQueueSize()); + assertEquals("dest has no memory usage", 0, queue.getMemoryPercentUsage()); + } + + public void testCreateDestinationWithSpacesAtEnds() throws Exception { + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + assertTrue("broker is not a slave", !broker.isSlave()); + // create 2 topics + broker.addTopic(getDestinationString() + "1 "); + broker.addTopic(" " + getDestinationString() + "2"); + broker.addTopic(" " + getDestinationString() + "3 "); + + + assertNotRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "1 "); + assertNotRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName= " + getDestinationString() + "2"); + assertNotRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName= " + getDestinationString() + "3 "); + + ObjectName topicObjName1 = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "1"); + ObjectName topicObjName2 = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "2"); + ObjectName topicObjName3 = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "3"); + + TopicViewMBean topic1 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName1, TopicViewMBean.class, true); + TopicViewMBean topic2 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName2, TopicViewMBean.class, true); + TopicViewMBean topic3 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName3, TopicViewMBean.class, true); + + assertEquals("topic1 Durable subscriber count", 0, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 0, topic2.getConsumerCount()); + assertEquals("topic3 Durable subscriber count", 0, topic3.getConsumerCount()); + + String topicName = getDestinationString(); + String selector = null; + + // create 1 subscriber for each topic + broker.createDurableSubscriber(clientID, "topic1.subscriber1", topicName + "1", selector); + broker.createDurableSubscriber(clientID, "topic2.subscriber1", topicName + "2", selector); + broker.createDurableSubscriber(clientID, "topic3.subscriber1", topicName + "3", selector); + + assertEquals("topic1 Durable subscriber count", 1, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 1, topic2.getConsumerCount()); + assertEquals("topic3 Durable subscriber count", 1, topic3.getConsumerCount()); + } + + protected void assertSendViaMBean() throws Exception { + String queueName = getDestinationString() + ".SendMBBean"; + + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + echo("Create QueueView MBean..."); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + broker.addQueue(queueName); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queueName); + + echo("Create QueueView MBean..."); + QueueViewMBean proxy = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + proxy.purge(); + + int count = 5; + for (int i = 0; i < count; i++) { + String body = "message:" + i; + + Map headers = new HashMap(); + headers.put("JMSCorrelationID", "MyCorrId"); + headers.put("JMSDeliveryMode", Boolean.FALSE); + headers.put("JMSXGroupID", "MyGroupID"); + headers.put("JMSXGroupSeq", 1234); + headers.put("JMSPriority", i + 1); + headers.put("JMSType", "MyType"); + headers.put("MyHeader", i); + headers.put("MyStringHeader", "StringHeader" + i); + + proxy.sendTextMessage(headers, body); + } + + browseAndVerify(proxy); + } + + private void browseAndVerify(QueueViewMBean proxy) throws Exception { + browseAndVerifyTypes(proxy, false); + } + + @SuppressWarnings("rawtypes") + private void browseAndVerifyTypes(QueueViewMBean proxy, boolean allStrings) throws Exception { + CompositeData[] compdatalist = proxy.browse(); + if (compdatalist.length == 0) { + fail("There is no message in the queue:"); + } + + for (int i = 0; i < compdatalist.length; i++) { + CompositeData cdata = compdatalist[i]; + + if (i == 0) { + echo("Columns: " + cdata.getCompositeType().keySet()); + } + + assertComplexData(i, cdata, "JMSCorrelationID", "MyCorrId"); + assertComplexData(i, cdata, "JMSPriority", i + 1); + assertComplexData(i, cdata, "JMSType", "MyType"); + assertComplexData(i, cdata, "JMSCorrelationID", "MyCorrId"); + assertComplexData(i, cdata, "JMSDeliveryMode", "NON-PERSISTENT"); + String expected = "{MyStringHeader=StringHeader" + i + ", MyHeader=" + i + "}"; + // The order of the properties is different when using the ibm jdk. + if (System.getProperty("java.vendor").equals("IBM Corporation")) { + expected = "{MyHeader=" + i + ", MyStringHeader=StringHeader" + i + "}"; + } + assertComplexData(i, cdata, "PropertiesText", expected); + + if (allStrings) { + Map stringProperties = CompositeDataHelper.getTabularMap(cdata, CompositeDataConstants.STRING_PROPERTIES); + assertEquals("stringProperties size()", 2, stringProperties.size()); + assertEquals("stringProperties.MyHeader", "StringHeader" + i, stringProperties.get("MyStringHeader")); + assertEquals("stringProperties.MyHeader", "" + i, stringProperties.get("MyHeader")); + + } else { + Map intProperties = CompositeDataHelper.getTabularMap(cdata, CompositeDataConstants.INT_PROPERTIES); + assertEquals("intProperties size()", 1, intProperties.size()); + assertEquals("intProperties.MyHeader", i, intProperties.get("MyHeader")); + + Map stringProperties = CompositeDataHelper.getTabularMap(cdata, CompositeDataConstants.STRING_PROPERTIES); + assertEquals("stringProperties size()", 1, stringProperties.size()); + assertEquals("stringProperties.MyHeader", "StringHeader" + i, stringProperties.get("MyStringHeader")); + } + + Map properties = CompositeDataHelper.getMessageUserProperties(cdata); + assertEquals("properties size()", 2, properties.size()); + assertEquals("properties.MyHeader", allStrings ? "" + i : i, properties.get("MyHeader")); + assertEquals("properties.MyHeader", "StringHeader" + i, properties.get("MyStringHeader")); + + assertComplexData(i, cdata, "JMSXGroupSeq", 1234); + assertComplexData(i, cdata, "JMSXGroupID", "MyGroupID"); + assertComplexData(i, cdata, "Text", "message:" + i); + } + } + + protected void assertSendCsnvViaMBean() throws Exception { + String queueName = getDestinationString() + ".SendMBBean"; + + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + echo("Create QueueView MBean..."); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + broker.addQueue(queueName); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queueName); + + echo("Create QueueView MBean..."); + QueueViewMBean proxy = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + proxy.purge(); + + int count = 5; + for (int i = 0; i < count; i++) { + String props = "body=message:" + i; + + props += ",JMSCorrelationID=MyCorrId"; + props += ",JMSDeliveryMode=1"; + props += ",JMSXGroupID=MyGroupID"; + props += ",JMSXGroupSeq=1234"; + props += ",JMSPriority=" + (i + 1); + props += ",JMSType=MyType"; + props += ",MyHeader=" + i; + props += ",MyStringHeader=StringHeader" + i; + + proxy.sendTextMessageWithProperties(props); + } + + browseAndVerifyTypes(proxy, true); + } + + protected void assertComplexData(int messageIndex, CompositeData cdata, String name, Object expected) { + Object value = cdata.get(name); + assertEquals("Message " + messageIndex + " CData field: " + name, expected, value); + } + + protected void assertQueueBrowseWorks() throws Exception { + Integer mbeancnt = mbeanServer.getMBeanCount(); + echo("Mbean count :" + mbeancnt); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + echo("Create QueueView MBean..."); + QueueViewMBean proxy = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + long concount = proxy.getConsumerCount(); + echo("Consumer Count :" + concount); + long messcount = proxy.getQueueSize(); + echo("current number of messages in the queue :" + messcount); + + // lets browse + CompositeData[] compdatalist = proxy.browse(); + if (compdatalist.length == 0) { + fail("There is no message in the queue:"); + } + String[] messageIDs = new String[compdatalist.length]; + + for (int i = 0; i < compdatalist.length; i++) { + CompositeData cdata = compdatalist[i]; + + if (i == 0) { + echo("Columns: " + cdata.getCompositeType().keySet()); + } + messageIDs[i] = (String)cdata.get("JMSMessageID"); + echo("message " + i + " : " + cdata.values()); + } + + TabularData table = proxy.browseAsTable(); + echo("Found tabular data: " + table); + assertTrue("Table should not be empty!", table.size() > 0); + + assertEquals("Queue size", MESSAGE_COUNT, proxy.getQueueSize()); + + String messageID = messageIDs[0]; + String newDestinationName = "queue://dummy.test.cheese"; + echo("Attempting to copy: " + messageID + " to destination: " + newDestinationName); + proxy.copyMessageTo(messageID, newDestinationName); + + assertEquals("Queue size", MESSAGE_COUNT, proxy.getQueueSize()); + + messageID = messageIDs[1]; + echo("Attempting to remove: " + messageID); + proxy.removeMessage(messageID); + + assertEquals("Queue size", MESSAGE_COUNT-1, proxy.getQueueSize()); + + echo("Worked!"); + } + + protected void assertCreateAndDestroyDurableSubscriptions() throws Exception { + // lets create a new topic + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + echo("Create QueueView MBean..."); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + broker.addTopic(getDestinationString()); + + assertEquals("Durable subscriber count", 0, broker.getDurableTopicSubscribers().length); + + String topicName = getDestinationString(); + String selector = null; + ObjectName name1 = broker.createDurableSubscriber(clientID, "subscriber1", topicName, selector); + broker.createDurableSubscriber(clientID, "subscriber2", topicName, selector); + assertEquals("Durable subscriber count", 2, broker.getInactiveDurableTopicSubscribers().length); + + assertNotNull("Should have created an mbean name for the durable subscriber!", name1); + + LOG.info("Created durable subscriber with name: " + name1); + + // now lets try destroy it + broker.destroyDurableSubscriber(clientID, "subscriber1"); + assertEquals("Durable subscriber count", 1, broker.getInactiveDurableTopicSubscribers().length); + } + + protected void assertConsumerCounts() throws Exception { + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + assertTrue("broker is not a slave", !broker.isSlave()); + // create 2 topics + broker.addTopic(getDestinationString() + "1"); + broker.addTopic(getDestinationString() + "2"); + + ObjectName topicObjName1 = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "1"); + ObjectName topicObjName2 = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "2"); + TopicViewMBean topic1 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName1, TopicViewMBean.class, true); + TopicViewMBean topic2 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName2, TopicViewMBean.class, true); + + assertEquals("topic1 Durable subscriber count", 0, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 0, topic2.getConsumerCount()); + + String topicName = getDestinationString(); + String selector = null; + + // create 1 subscriber for each topic + broker.createDurableSubscriber(clientID, "topic1.subscriber1", topicName + "1", selector); + broker.createDurableSubscriber(clientID, "topic2.subscriber1", topicName + "2", selector); + + assertEquals("topic1 Durable subscriber count", 1, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 1, topic2.getConsumerCount()); + + // create 1 more subscriber for topic1 + broker.createDurableSubscriber(clientID, "topic1.subscriber2", topicName + "1", selector); + + assertEquals("topic1 Durable subscriber count", 2, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 1, topic2.getConsumerCount()); + + // destroy topic1 subscriber + broker.destroyDurableSubscriber(clientID, "topic1.subscriber1"); + + assertEquals("topic1 Durable subscriber count", 1, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 1, topic2.getConsumerCount()); + + // destroy topic2 subscriber + broker.destroyDurableSubscriber(clientID, "topic2.subscriber1"); + + assertEquals("topic1 Durable subscriber count", 1, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 0, topic2.getConsumerCount()); + + // destroy remaining topic1 subscriber + broker.destroyDurableSubscriber(clientID, "topic1.subscriber2"); + + assertEquals("topic1 Durable subscriber count", 0, topic1.getConsumerCount()); + assertEquals("topic2 Durable subscriber count", 0, topic2.getConsumerCount()); + } + + protected void assertProducerCounts() throws Exception { + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + assertTrue("broker is not a slave", !broker.isSlave()); + // create 2 topics + broker.addTopic(getDestinationString() + "1"); + broker.addTopic(getDestinationString() + "2"); + + ObjectName topicObjName1 = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "1"); + ObjectName topicObjName2 = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=" + getDestinationString() + "2"); + TopicViewMBean topic1 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName1, TopicViewMBean.class, true); + TopicViewMBean topic2 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName2, TopicViewMBean.class, true); + + assertEquals("topic1 Producer count", 0, topic1.getProducerCount()); + assertEquals("topic2 Producer count", 0, topic2.getProducerCount()); + 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); + + 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); + + 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); + + 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); + + 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); + + assertEquals("topic1 Producer count", 0, topic1.getProducerCount()); + assertEquals("topic2 Producer count", 0, topic2.getProducerCount()); + + MessageProducer producer4 = session.createProducer(null); + Thread.sleep(500); + assertEquals(1, broker.getDynamicDestinationProducers().length); + producer4.close(); + Thread.sleep(500); + + 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(); + } + })); + return objectName; + } + + protected ObjectName assertNotRegisteredObjectName(String name) throws MalformedObjectNameException, NullPointerException { + ObjectName objectName = new ObjectName(name); + if (mbeanServer.isRegistered(objectName)) { + fail("Found the MBean!: " + objectName); + } else { + echo("Bean not registered Registered: " + objectName); + } + return objectName; + } + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + useTopic = false; + super.setUp(); + ManagementContext managementContext = broker.getManagementContext(); + mbeanServer = managementContext.getMBeanServer(); + } + + @Override + protected void tearDown() throws Exception { + if (waitForKeyPress) { + // We are running from the command line so let folks browse the + // mbeans... + System.out.println(); + System.out.println("Press enter to terminate the program."); + System.out.println("In the meantime you can use your JMX console to view the current MBeans"); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + reader.readLine(); + } + + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString()); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.setDeleteAllMessagesOnStartup(true); + answer.setUseJmx(true); + + // apply memory limit so that %usage is visible + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setMemoryLimit(1024*1024*4); + policyMap.setDefaultEntry(defaultEntry); + answer.setDestinationPolicy(policyMap); + + // allow options to be visible via jmx + answer.setDestinations(new ActiveMQDestination[]{new ActiveMQQueue(QUEUE_WITH_OPTIONS + "?topQueue=true&hasOptions=2")}); + + answer.addConnector(bindAddress); + return answer; + } + + protected void useConnection(Connection connection) throws Exception { + connection.setClientID(clientID); + connection.start(); + Session session = connection.createSession(transacted, authMode); + destination = createDestination(); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message message = session.createTextMessage("Message: " + i); + message.setIntProperty("counter", i); + message.setJMSCorrelationID("MyCorrelationID"); + message.setJMSReplyTo(new ActiveMQQueue("MyReplyTo")); + message.setJMSType("MyType"); + message.setJMSPriority(5); + producer.send(message); + } + Thread.sleep(1000); + } + + protected void useConnectionWithBlobMessage(Connection connection) throws Exception { + connection.setClientID(clientID); + connection.start(); + ActiveMQSession session = (ActiveMQSession) connection.createSession(transacted, authMode); + destination = createDestination(); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BlobMessage message = session.createBlobMessage(new URL("http://foo.bar/test")); + message.setIntProperty("counter", i); + message.setJMSCorrelationID("MyCorrelationID"); + message.setJMSReplyTo(new ActiveMQQueue("MyReplyTo")); + message.setJMSType("MyType"); + message.setJMSPriority(5); + producer.send(message); + } + Thread.sleep(1000); + } + + protected void useConnectionWithByteMessage(Connection connection) throws Exception { + connection.setClientID(clientID); + connection.start(); + ActiveMQSession session = (ActiveMQSession) connection.createSession(transacted, authMode); + destination = createDestination(); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage message = session.createBytesMessage(); + message.writeBytes(("Message: " + i).getBytes()); + message.setIntProperty("counter", i); + message.setJMSCorrelationID("MyCorrelationID"); + message.setJMSReplyTo(new ActiveMQQueue("MyReplyTo")); + message.setJMSType("MyType"); + message.setJMSPriority(5); + producer.send(message); + } + Thread.sleep(1000); + } + + protected void echo(String text) { + //LOG.info(text); + } + + protected String getSecondDestinationString() { + return "test.new.destination." + getClass() + "." + getName(); + } + + 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); + + assertEquals(0, broker.getDynamicDestinationProducers().length); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + Destination dest1 = session.createTopic("DynamicDest-1"); + Destination dest2 = session.createTopic("DynamicDest-2"); + Destination dest3 = session.createQueue("DynamicDest-3"); + + // Wait a bit to let the producer get registered. + Thread.sleep(100); + + assertEquals(1, broker.getDynamicDestinationProducers().length); + + ObjectName viewName = broker.getDynamicDestinationProducers()[0]; + assertNotNull(viewName); + 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); + 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); + 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); + assertEquals(((ActiveMQDestination)dest3).getPhysicalName(), view.getDestinationName()); + assertTrue(view.isDestinationQueue()); + assertFalse(view.isDestinationTopic()); + assertFalse(view.isDestinationTemporary()); + + producer.close(); + Thread.sleep(200); + assertEquals(0, broker.getDynamicDestinationProducers().length); + } + + public void testTempQueueJMXDelete() throws Exception { + connection = connectionFactory.createConnection(); + + connection.setClientID(clientID); + connection.start(); + Session session = connection.createSession(transacted, authMode); + ActiveMQTempQueue tQueue = (ActiveMQTempQueue) session.createTemporaryQueue(); + Thread.sleep(1000); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=" + + JMXSupport.encodeObjectNamePart(tQueue.getDestinationTypeAsString()) + + ",destinationName=" + JMXSupport.encodeObjectNamePart(tQueue.getPhysicalName())); + + // 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! + } + } + + // Test for AMQ-3029 + public void testBrowseBlobMessages() throws Exception { + connection = connectionFactory.createConnection(); + useConnectionWithBlobMessage(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + CompositeData[] compdatalist = queue.browse(); + int initialQueueSize = compdatalist.length; + if (initialQueueSize == 0) { + fail("There is no message in the queue:"); + } + else { + echo("Current queue size: " + initialQueueSize); + } + int messageCount = initialQueueSize; + String[] messageIDs = new String[messageCount]; + for (int i = 0; i < messageCount; i++) { + CompositeData cdata = compdatalist[i]; + String messageID = (String) cdata.get("JMSMessageID"); + assertNotNull("Should have a message ID for message " + i, messageID); + + messageIDs[i] = messageID; + } + + assertTrue("dest has some memory usage", queue.getMemoryPercentUsage() > 0); + } + + public void testDestinationOptionsAreVisible() throws Exception { + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + QUEUE_WITH_OPTIONS ); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + assertEquals("name match", QUEUE_WITH_OPTIONS, queue.getName()); + + String options = queue.getOptions(); + LOG.info("Got options: " + options); + + Map optionsMap = URISupport.parseQuery(options); + assertEquals("got a map", 2, optionsMap.size()); + assertTrue("matches our options", optionsMap.containsKey("hasOptions")); + assertTrue("matches our options", optionsMap.containsKey("topQueue")); + + assertTrue("matches our options", optionsMap.containsValue("true")); + assertTrue("matches our options", optionsMap.containsValue("2")); + } + + 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); + + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + Thread.sleep(100); + + assertTrue(broker.getQueueSubscribers().length == 1); + + ObjectName subscriptionName = broker.getQueueSubscribers()[0]; + LOG.info("Looking for Subscription: " + subscriptionName); + + SubscriptionViewMBean subscriberView = + MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, subscriptionName, SubscriptionViewMBean.class, true); + assertNotNull(subscriberView); + + ObjectName connectionName = subscriberView.getConnection(); + LOG.info("Looking for Connection: " + connectionName); + assertNotNull(connectionName); + ConnectionViewMBean connectionView = + MBeanServerInvocationHandler.newProxyInstance( + mbeanServer, connectionName, ConnectionViewMBean.class, true); + assertNotNull(connectionView); + + // Our consumer plus one advisory consumer. + assertEquals(2, connectionView.getConsumers().length); + + assertEquals("client id match", "MBeanTest", connectionView.getClientId()); + + // Check that the subscription view we found earlier is in this list. + boolean found = false; + for (ObjectName name : connectionView.getConsumers()) { + if (name.equals(subscriptionName)) { + found = true; + } + } + assertTrue("We should have found: " + subscriptionName, found); + + // Our producer and no others. + assertEquals(1, connectionView.getProducers().length); + + // Bean should detect the updates. + queueConsumer.close(); + producer.close(); + + Thread.sleep(200); + + // Only an advisory consumers now. + assertEquals(1, connectionView.getConsumers().length); + assertEquals(0, connectionView.getProducers().length); + } + + 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); + + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + echo("Create QueueView MBean..."); + 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"); + + Thread.sleep(100); + + assertEquals("Durable subscriber count", 2, broker.getDurableTopicSubscribers().length); + assertEquals("Durable subscriber count", 0, broker.getInactiveDurableTopicSubscribers().length); + + durableConsumer1.close(); + durableConsumer2.close(); + + Thread.sleep(100); + + assertEquals("Durable subscriber count", 0, broker.getDurableTopicSubscribers().length); + assertEquals("Durable subscriber count", 2, broker.getInactiveDurableTopicSubscribers().length); + + session.unsubscribe("subscription1"); + + Thread.sleep(100); + + assertEquals("Inactive Durable subscriber count", 1, broker.getInactiveDurableTopicSubscribers().length); + + session.unsubscribe("subscription2"); + + assertEquals("Inactive Durable subscriber count", 0, broker.getInactiveDurableTopicSubscribers().length); + } + + public void testUserNamePopulated() throws Exception { + doTestUserNameInMBeans(true); + } + + public void testUserNameNotPopulated() throws Exception { + doTestUserNameInMBeans(false); + } + + @SuppressWarnings("unused") + private void doTestUserNameInMBeans(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); + + assertTrue(broker.getQueueProducers().length == 1); + assertTrue(broker.getTopicSubscribers().length == 2); + assertTrue(broker.getQueueSubscribers().length == 1); + + ObjectName producerName = broker.getQueueProducers()[0]; + ProducerViewMBean producerView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, producerName, ProducerViewMBean.class, true); + assertNotNull(producerView); + + if (expect) { + assertEquals("admin", producerView.getUserName()); + } else { + assertNull(producerView.getUserName()); + } + + for (ObjectName name : broker.getTopicSubscribers()) { + SubscriptionViewMBean subscriberView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, name, SubscriptionViewMBean.class, true); + if (expect) { + assertEquals("admin", subscriberView.getUserName()); + } else { + assertNull(subscriberView.getUserName()); + } + } + + for (ObjectName name : broker.getQueueSubscribers()) { + SubscriptionViewMBean subscriberView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, name, SubscriptionViewMBean.class, true); + if (expect) { + assertEquals("admin", subscriberView.getUserName()); + } else { + assertNull(subscriberView.getUserName()); + } + } + ObjectName query = //new ObjectName(domain + ":type=Broker,brokerName=localhost,connector=*," + "connectorName=*,connectionName=MBeanTest"); + BrokerMBeanSupport.createConnectionQuery(domain, "localhost", connection.getClientID()); + + Set names = mbeanServer.queryNames(query, null); + boolean found = false; + for (ObjectName name : names) { + if (name.toString().endsWith("connectionName=MBeanTest")) { + + ConnectionViewMBean connectionView = + MBeanServerInvocationHandler.newProxyInstance(mbeanServer, name, ConnectionViewMBean.class, true); + assertNotNull(connectionView); + + if (expect) { + assertEquals("admin", connectionView.getUserName()); + } else { + assertNull(connectionView.getUserName()); + } + + found = true; + break; + } + } + + assertTrue("Should find the connection's ManagedTransportConnection", found); + } + + public void testMoveMessagesToRetainOrder() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + String newDestination = getSecondDestinationString(); + queue.moveMatchingMessagesTo("", newDestination); + + queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + newDestination); + + queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + int movedSize = MESSAGE_COUNT; + assertEquals("Unexpected number of messages ",movedSize,queue.getQueueSize()); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(newDestination); + MessageConsumer consumer = session.createConsumer(destination); + + int last = -1; + int current = -1; + Message message = null; + while ((message = consumer.receive(2000)) != null) { + if (message.propertyExists("counter")) { + current = message.getIntProperty("counter"); + assertEquals(last, current - 1); + last = current; + } + } + + // now lets remove them by selector + queue.removeMatchingMessages(""); + + assertEquals("Should have no more messages in the queue: " + queueViewMBeanName, 0, queue.getQueueSize()); + assertEquals("dest has no memory usage", 0, queue.getMemoryPercentUsage()); + } + + public void testConnectionCounts() throws Exception { + + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + assertEquals(0, broker.getCurrentConnectionsCount()); + + connection = connectionFactory.createConnection(); + useConnection(connection); + + assertEquals(1, broker.getCurrentConnectionsCount()); + connection.close(); + assertEquals(0, broker.getCurrentConnectionsCount()); + assertEquals(1, broker.getTotalConnectionsCount()); + } + + public void testCopyMessagesToRetainOrder() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + String newDestination = getSecondDestinationString(); + queue.copyMatchingMessagesTo("", newDestination); + + queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + newDestination ); + + queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + int movedSize = MESSAGE_COUNT; + assertEquals("Unexpected number of messages ",movedSize,queue.getQueueSize()); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(newDestination); + MessageConsumer consumer = session.createConsumer(destination); + + int last = -1; + int current = -1; + Message message = null; + while ((message = consumer.receive(2000)) != null) { + if (message.propertyExists("counter")) { + current = message.getIntProperty("counter"); + assertEquals(last, current - 1); + last = current; + } + } + + // now lets remove them by selector + queue.removeMatchingMessages(""); + + assertEquals("Should have no more messages in the queue: " + queueViewMBeanName, 0, queue.getQueueSize()); + assertEquals("dest has no memory usage", 0, queue.getMemoryPercentUsage()); + } + + public void testRemoveMatchingMessageRetainOrder() throws Exception { + connection = connectionFactory.createConnection(); + useConnection(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + String queueName = getDestinationString(); + queue.removeMatchingMessages("counter < 10"); + + int newSize = MESSAGE_COUNT - 10; + assertEquals("Unexpected number of messages ", newSize, queue.getQueueSize()); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(queueName); + MessageConsumer consumer = session.createConsumer(destination); + + int last = 9; + int current = 0; + Message message = null; + while ((message = consumer.receive(2000)) != null) { + if (message.propertyExists("counter")) { + current = message.getIntProperty("counter"); + assertEquals(last, current - 1); + last = current; + } + } + + // now lets remove them by selector + queue.removeMatchingMessages(""); + + assertEquals("Should have no more messages in the queue: " + queueViewMBeanName, 0, queue.getQueueSize()); + assertEquals("dest has no memory usage", 0, queue.getMemoryPercentUsage()); + } + + public void testBrowseBytesMessages() throws Exception { + connection = connectionFactory.createConnection(); + useConnectionWithByteMessage(connection); + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + + QueueViewMBean queue = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + CompositeData[] compdatalist = queue.browse(); + int initialQueueSize = compdatalist.length; + if (initialQueueSize == 0) { + fail("There is no message in the queue:"); + } + else { + echo("Current queue size: " + initialQueueSize); + } + int messageCount = initialQueueSize; + String[] messageIDs = new String[messageCount]; + for (int i = 0; i < messageCount; i++) { + CompositeData cdata = compdatalist[i]; + String messageID = (String) cdata.get("JMSMessageID"); + assertNotNull("Should have a message ID for message " + i, messageID); + messageIDs[i] = messageID; + + Byte[] preview = (Byte[]) cdata.get(CompositeDataConstants.BODY_PREVIEW); + assertNotNull("should be a preview", preview); + assertTrue("not empty", preview.length > 0); + } + + assertTrue("dest has some memory usage", queue.getMemoryPercentUsage() > 0); + + // consume all the messages + echo("Attempting to consume all bytes messages from: " + destination); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + for (int i=0; i 0); + assertEquals("counter in order", i, intProperties.get("counter")); + } + + echo("Attempting to consume 5 bytes messages from: " + destination); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + for (int i=0; i<5; i++) { + Message message = consumer.receive(5000); + assertNotNull(message); + assertEquals("ordered", i, message.getIntProperty("counter")); + echo("Consumed: " + message.getIntProperty("counter")); + } + consumer.close(); + session.close(); + connection.close(); + + // browse again and verify order + compdatalist = queue.browse(); + initialQueueSize = compdatalist.length; + assertEquals("5 gone", MESSAGE_COUNT - 5, initialQueueSize); + + messageCount = initialQueueSize; + for (int i = 0; i < messageCount - 4; i++) { + CompositeData cdata = compdatalist[i]; + + Map intProperties = CompositeDataHelper.getTabularMap(cdata, CompositeDataConstants.INT_PROPERTIES); + assertTrue("not empty", intProperties.size() > 0); + assertEquals("counter in order", i + 5, intProperties.get("counter")); + echo("Got: " + intProperties.get("counter")); + } + } + + public void testAddRemoveConnectorBrokerView() throws Exception { + + ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean brokerView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + Map connectors = brokerView.getTransportConnectors(); + LOG.info("Connectors: " + connectors); + assertEquals("one connector", 1, connectors.size()); + + ConnectorViewMBean connector = getProxyToConnectionView("tcp"); + assertNotNull(connector); + + String name = connectors.keySet().iterator().next().toString(); + + brokerView.removeConnector(name); + + connectors = brokerView.getTransportConnectors(); + assertEquals("empty", 0, connectors.size()); + + name = brokerView.addConnector("tcp://0.0.0.0:0"); + + connector = getProxyToConnectionView("tcp"); + assertNotNull(connector); + + connectors = brokerView.getTransportConnectors(); + LOG.info("Connectors: " + connectors); + assertEquals("one connector", 1, connectors.size()); + assertTrue("name is in map: " + connectors.keySet(), connectors.keySet().contains(name)); + } + + public void testConnectorView() throws Exception { + ConnectorViewMBean connector = getProxyToConnectionView("tcp"); + assertNotNull(connector); + + assertFalse(connector.isRebalanceClusterClients()); + assertFalse(connector.isUpdateClusterClientsOnRemove()); + assertFalse(connector.isUpdateClusterClients()); + assertFalse(connector.isAllowLinkStealingEnabled()); + } + + protected ConnectorViewMBean getProxyToConnectionView(String connectionType) throws Exception { + ObjectName connectorQuery = new ObjectName( + "org.apache.activemq:type=Broker,brokerName=localhost,connector=clientConnectors,connectorName="+connectionType+"_//*"); + + Set results = broker.getManagementContext().queryNames(connectorQuery, null); + + if (results == null || results.isEmpty() || results.size() > 1) { + throw new Exception("Unable to find the exact Connector instance."); + } + + ConnectorViewMBean proxy = (ConnectorViewMBean) broker.getManagementContext() + .newProxyInstance(results.iterator().next(), ConnectorViewMBean.class, true); + return proxy; + } + + public void testDynamicProducers() throws Exception { + connection = connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + ObjectName query = new ObjectName(domain + ":type=Broker,brokerName=localhost,endpoint=dynamicProducer,*"); + Set mbeans = mbeanServer.queryMBeans(query, null); + assertEquals(mbeans.size(), 1); + producer.close(); + } + + public void testDurableSubQuery() throws Exception { + connection = connectionFactory.createConnection(); + connection.setClientID("test"); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = session.createDurableSubscriber(session.createTopic("test.topic"), "test.consumer"); + + ObjectName query = new ObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=test.topic,endpoint=Consumer,consumerId=Durable(*),*"); + Set mbeans = mbeanServer.queryMBeans(query, null); + assertEquals(mbeans.size(), 1); + sub.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/PurgeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/PurgeTest.java new file mode 100644 index 0000000000..ce8e3aecb0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/PurgeTest.java @@ -0,0 +1,250 @@ +/** + * 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.broker.jmx; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.MBeanServer; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import junit.framework.Test; +import junit.textui.TestRunner; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.memory.MemoryPersistenceAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A specific test of Queue.purge() functionality + */ +public class PurgeTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(PurgeTest.class); + + protected MBeanServer mbeanServer; + protected String domain = "org.apache.activemq"; + protected String clientID = "foo"; + + protected Connection connection; + protected boolean transacted; + protected int authMode = Session.AUTO_ACKNOWLEDGE; + protected int messageCount = 10; + public PersistenceAdapter persistenceAdapter; + + public static void main(String[] args) { + TestRunner.run(PurgeTest.class); + } + + public static Test suite() { + return suite(PurgeTest.class); + } + + public void testPurge() throws Exception { + // Send some messages + connection = connectionFactory.createConnection(); + connection.setClientID(clientID); + connection.start(); + Session session = connection.createSession(transacted, authMode); + destination = createDestination(); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < messageCount; i++) { + Message message = session.createTextMessage("Message: " + i); + producer.send(message); + } + + // Now get the QueueViewMBean and purge + String objectNameStr = broker.getBrokerObjectName().toString(); + objectNameStr += ",destinationType=Queue,destinationName="+getDestinationString(); + ObjectName queueViewMBeanName = assertRegisteredObjectName(objectNameStr); + QueueViewMBean proxy = (QueueViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + long count = proxy.getQueueSize(); + assertEquals("Queue size", count, messageCount); + + proxy.purge(); + count = proxy.getQueueSize(); + assertEquals("Queue size", count, 0); + assertEquals("Browse size", proxy.browseMessages().size(), 0); + + // Queues have a special case once there are more than a thousand + // dead messages, make sure we hit that. + messageCount += 1000; + for (int i = 0; i < messageCount; i++) { + Message message = session.createTextMessage("Message: " + i); + producer.send(message); + } + + count = proxy.getQueueSize(); + assertEquals("Queue size", count, messageCount); + + proxy.purge(); + count = proxy.getQueueSize(); + assertEquals("Queue size", count, 0); + assertEquals("Browse size", proxy.browseMessages().size(), 0); + + producer.close(); + } + + public void initCombosForTestDelete() { + addCombinationValues("persistenceAdapter", new Object[] {new MemoryPersistenceAdapter(), new KahaDBPersistenceAdapter()}); + } + + public void testDeleteSameProducer() throws Exception { + connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = createDestination(); + + MessageProducer producer = session.createProducer(destination); + Message message = session.createTextMessage("Test Message"); + producer.send(message); + + MessageConsumer consumer = session.createConsumer(destination); + + Message received = consumer.receive(1000); + assertEquals(message, received); + + ObjectName brokerViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean brokerProxy = (BrokerViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerViewMBeanName, BrokerViewMBean.class, true); + + brokerProxy.removeQueue(getDestinationString()); + producer.send(message); + + received = consumer.receive(1000); + + assertNotNull("Message not received", received); + assertEquals(message, received); + } + + public void testDelete() throws Exception { + // Send some messages + connection = connectionFactory.createConnection(); + connection.setClientID(clientID); + connection.start(); + Session session = connection.createSession(transacted, authMode); + destination = createDestination(); + sendMessages(session, messageCount); + + // Now get the QueueViewMBean and purge + + ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + QueueViewMBean queueProxy = (QueueViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + ObjectName brokerViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + BrokerViewMBean brokerProxy = (BrokerViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerViewMBeanName, BrokerViewMBean.class, true); + + long count = queueProxy.getQueueSize(); + assertEquals("Queue size", count, messageCount); + + brokerProxy.removeQueue(getDestinationString()); + + sendMessages(session, messageCount); + + queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + queueProxy = (QueueViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + count = queueProxy.getQueueSize(); + assertEquals("Queue size", count, messageCount); + + queueProxy.purge(); + + // Queue have a special case once there are more than a thousand + // dead messages, make sure we hit that. + messageCount += 1000; + sendMessages(session, messageCount); + + count = queueProxy.getQueueSize(); + assertEquals("Queue size", count, messageCount); + + brokerProxy.removeQueue(getDestinationString()); + + sendMessages(session, messageCount); + + queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + queueProxy = (QueueViewMBean)MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + + count = queueProxy.getQueueSize(); + assertEquals("Queue size", count, messageCount); + } + + private void sendMessages(Session session, int count) throws Exception { + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < messageCount; i++) { + Message message = session.createTextMessage("Message: " + i); + producer.send(message); + } + } + + protected ObjectName assertRegisteredObjectName(String name) throws MalformedObjectNameException, NullPointerException { + ObjectName objectName = new ObjectName(name); + if (mbeanServer.isRegistered(objectName)) { + echo("Bean Registered: " + objectName); + } else { + fail("Could not find MBean!: " + objectName); + } + return objectName; + } + + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + useTopic = false; + super.setUp(); + mbeanServer = broker.getManagementContext().getMBeanServer(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseJmx(true); + answer.setEnableStatistics(true); + answer.addConnector(bindAddress); + answer.setPersistenceAdapter(persistenceAdapter); + answer.deleteAllMessages(); + return answer; + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString()); + } + + protected void echo(String text) { + LOG.info(text); + } + + /** + * Returns the name of the destination used in this test case + */ + protected String getDestinationString() { + return getClass().getName() + "." + getName(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/TransportConnectorMBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/TransportConnectorMBeanTest.java new file mode 100644 index 0000000000..6f55e3de38 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/jmx/TransportConnectorMBeanTest.java @@ -0,0 +1,140 @@ +/** + * 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.broker.jmx; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertEquals; + +import java.net.Socket; +import java.util.Set; + +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.JMXSupport; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransportConnectorMBeanTest { + private static final Logger LOG = LoggerFactory.getLogger(TransportConnectorMBeanTest.class); + + BrokerService broker; + + @Test + public void verifyRemoteAddressInMbeanName() throws Exception { + doVerifyRemoteAddressInMbeanName(true); + } + + @Test + public void verifyRemoteAddressNotInMbeanName() throws Exception { + doVerifyRemoteAddressInMbeanName(false); + } + + @Test + public void verifyClientIdNetwork() throws Exception { + doVerifyClientIdNetwork(false); + } + + @Test + public void verifyClientIdDuplexNetwork() throws Exception { + doVerifyClientIdNetwork(true); + } + + private void doVerifyClientIdNetwork(boolean duplex) throws Exception { + createBroker(true); + + BrokerService networked = new BrokerService(); + networked.setBrokerName("networked"); + networked.setPersistent(false); + NetworkConnector nc = networked.addNetworkConnector("static:" + broker.getTransportConnectors().get(0).getPublishableConnectString()); + nc.setDuplex(duplex); + networked.start(); + + try { + assertTrue("presence of mbean with clientId", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Set registeredMbeans = getRegisteredMbeans(); + return match("_outbound", registeredMbeans); + } + })); + + } finally { + networked.stop(); + } + } + + private void doVerifyRemoteAddressInMbeanName(boolean allowRemoteAddress) throws Exception { + createBroker(allowRemoteAddress); + ActiveMQConnection connection = createConnection(); + Set registeredMbeans = getRegisteredMbeans(); + assertEquals("presence of mbean with clientId", true, match(connection.getClientID(), registeredMbeans)); + assertEquals("presence of mbean with local port", allowRemoteAddress, match(extractLocalPort(connection), registeredMbeans)); + } + + @After + public void stopBroker() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + private boolean match(String s, Set registeredMbeans) { + String encodedName = JMXSupport.encodeObjectNamePart(s); + for (ObjectName name : registeredMbeans) { + LOG.info("checking for match:" + encodedName + ", with: " + name.toString()); + if (name.toString().contains(encodedName)) { + return true; + } + } + return false; + } + + private String extractLocalPort(ActiveMQConnection connection) throws Exception { + Socket socket = connection.getTransport().narrow(Socket.class); + return String.valueOf(socket.getLocalPort()); + } + + private Set getRegisteredMbeans() throws Exception { + // need a little sleep to ensure JMX is up to date + Thread.sleep(200); + return broker.getManagementContext().queryNames(null, null); + } + + private ActiveMQConnection createConnection() throws Exception { + final String opts = "?jms.watchTopicAdvisories=false"; + ActiveMQConnection connection = (ActiveMQConnection) + new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri() + opts).createConnection(); + connection.start(); + return connection; + } + + private void createBroker(boolean allowRemoteAddressInMbeanNames) throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.addConnector("tcp://localhost:0"); + broker.getManagementContext().setAllowRemoteAddressInMBeanNames(allowRemoteAddressInMbeanNames); + broker.start(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/mKahaDBXARecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/mKahaDBXARecoveryBrokerTest.java new file mode 100644 index 0000000000..4cc57ba27c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/mKahaDBXARecoveryBrokerTest.java @@ -0,0 +1,62 @@ +/** + * 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.broker; + +import java.util.LinkedList; +import java.util.List; + +import junit.framework.Test; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; + +public class mKahaDBXARecoveryBrokerTest extends XARecoveryBrokerTest { + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + super.configureBroker(broker); + + MultiKahaDBPersistenceAdapter mKahaDB = new MultiKahaDBPersistenceAdapter(); + List adapters = new LinkedList(); + FilteredKahaDBPersistenceAdapter defaultEntry = new FilteredKahaDBPersistenceAdapter(); + defaultEntry.setPersistenceAdapter(new KahaDBPersistenceAdapter()); + adapters.add(defaultEntry); + + FilteredKahaDBPersistenceAdapter special = new FilteredKahaDBPersistenceAdapter(); + special.setDestination(new ActiveMQQueue("special")); + special.setPersistenceAdapter(new KahaDBPersistenceAdapter()); + adapters.add(special); + + mKahaDB.setFilteredPersistenceAdapters(adapters); + broker.setPersistenceAdapter(mKahaDB); + } + + public static Test suite() { + return suite(mKahaDBXARecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + protected ActiveMQDestination createDestination() { + return new ActiveMQQueue("test,special"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/mLevelDBXARecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/mLevelDBXARecoveryBrokerTest.java new file mode 100644 index 0000000000..147d89a02f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/mLevelDBXARecoveryBrokerTest.java @@ -0,0 +1,69 @@ +/** + * 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.broker; + +import junit.framework.Test; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; +import org.apache.activemq.store.leveldb.LevelDBPersistenceAdapter; + +import java.util.LinkedList; +import java.util.List; + +public class mLevelDBXARecoveryBrokerTest extends XARecoveryBrokerTest { + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + super.configureBroker(broker); + + MultiKahaDBPersistenceAdapter mKahaDB = new MultiKahaDBPersistenceAdapter(); + List adapters = new LinkedList(); + FilteredKahaDBPersistenceAdapter defaultEntry = new FilteredKahaDBPersistenceAdapter(); + defaultEntry.setPersistenceAdapter(new LevelDBPersistenceAdapter()); + adapters.add(defaultEntry); + + FilteredKahaDBPersistenceAdapter special = new FilteredKahaDBPersistenceAdapter(); + special.setDestination(new ActiveMQQueue("special")); + special.setPersistenceAdapter(new LevelDBPersistenceAdapter()); + adapters.add(special); + + mKahaDB.setFilteredPersistenceAdapters(adapters); + broker.setPersistenceAdapter(mKahaDB); + } + + public static Test suite() { + return suite(mLevelDBXARecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + protected ActiveMQDestination createDestination() { + return new ActiveMQQueue("test,special"); + } + + public void testQueuePersistentPreparedAcksAvailableAfterRestartAndRollback() throws Exception { + // super.testQueuePersistentPreparedAcksAvailableAfterRestartAndRollback(); + } + public void testQueuePersistentUncommittedAcksLostOnRestart() throws Exception { + // super.testQueuePersistentUncommittedAcksLostOnRestart(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/message/security/MessageAuthenticationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/message/security/MessageAuthenticationTest.java new file mode 100644 index 0000000000..092c554c5f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/message/security/MessageAuthenticationTest.java @@ -0,0 +1,99 @@ +/** + * + * 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.broker.message.security; + +import java.io.IOException; + +import javax.jms.Connection; +import javax.jms.Session; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; +import javax.jms.JMSException; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.security.MessageAuthorizationPolicy; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.spring.ConsumerBean; + +/** + * + */ +public class MessageAuthenticationTest extends EmbeddedBrokerTestSupport { + + private Connection connection; + + public void testSendInvalidMessage() throws Exception { + if (connection == null) { + connection = createConnection(); + } + connection.start(); + + ConsumerBean messageList = new ConsumerBean(); + messageList.setVerbose(true); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Destination destination = new ActiveMQQueue("MyQueue"); + + MessageConsumer c1 = session.createConsumer(destination); + + c1.setMessageListener(messageList); + + MessageProducer producer = session.createProducer(destination); + assertNotNull(producer); + + producer.send(createMessage(session, "invalidBody", "myHeader", "xyz")); + producer.send(createMessage(session, "validBody", "myHeader", "abc")); + + messageList.assertMessagesArrived(1); + assertEquals("validBody", ((TextMessage) messageList.flushMessages().get(0)).getText()); + } + + private javax.jms.Message createMessage(Session session, String body, String header, String value) throws JMSException { + TextMessage msg = session.createTextMessage(body); + msg.setStringProperty(header, value); + return msg; + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.setMessageAuthorizationPolicy(new MessageAuthorizationPolicy() { + public boolean isAllowedToConsume(ConnectionContext context, Message message) { + try { + Object value = message.getProperty("myHeader"); + return "abc".equals(value); + } + catch (IOException e) { + System.out.println("Caught: " + e); + e.printStackTrace(); + return false; + } + } + }); + answer.addConnector(bindAddress); + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/out-of-order-broker-elements.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/out-of-order-broker-elements.xml new file mode 100644 index 0000000000..245d946f50 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/out-of-order-broker-elements.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/partition/SpringPartitionBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/partition/SpringPartitionBrokerTest.java new file mode 100644 index 0000000000..dcf4e69e5f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/partition/SpringPartitionBrokerTest.java @@ -0,0 +1,53 @@ +/** + * 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.broker.partition; + +import junit.framework.TestCase; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.partition.PartitionBrokerPlugin; +import org.apache.activemq.partition.dto.Partitioning; + +/** + */ +public class SpringPartitionBrokerTest extends TestCase { + + public void testCreatePartitionBroker() throws Exception { + + BrokerService broker = BrokerFactory.createBroker("xbean:activemq-partition.xml"); + assertEquals(1, broker.getPlugins().length); + PartitionBrokerPlugin plugin = (PartitionBrokerPlugin)broker.getPlugins()[0]; + Partitioning config = plugin.getConfig(); + assertEquals(2, config.getBrokers().size()); + + Object o; + String json = "{\n" + + " \"by_client_id\":{\n" + + " \"client1\":{\"ids\":[\"broker1\"]},\n" + + " \"client2\":{\"ids\":[\"broker1\",\"broker2\"]}\n" + + " },\n" + + " \"brokers\":{\n" + + " \"broker1\":\"tcp://localhost:61616\",\n" + + " \"broker2\":\"tcp://localhost:61616\"\n" + + " }\n" + + "}"; + Partitioning expected = Partitioning.MAPPER.readValue(json, Partitioning.class); + assertEquals(expected.toString(), config.toString()); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer0Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer0Test.java new file mode 100644 index 0000000000..3cfd59545d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer0Test.java @@ -0,0 +1,178 @@ +/** + * 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.broker.policy; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.util.concurrent.TimeUnit; + +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.AbortSlowAckConsumerStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class AbortSlowAckConsumer0Test extends AbortSlowConsumer0Test { + private static final Logger LOG = LoggerFactory.getLogger(AbortSlowAckConsumer0Test.class); + protected long maxTimeSinceLastAck = 5 * 1000; + + AbortSlowAckConsumerStrategy strategy; + + public AbortSlowAckConsumer0Test(Boolean isTopic) { + super(isTopic); + } + + @Override + protected AbortSlowAckConsumerStrategy createSlowConsumerStrategy() { + AbortSlowAckConsumerStrategy strategy = new AbortSlowAckConsumerStrategy(); + strategy.setAbortConnection(abortConnection); + strategy.setCheckPeriod(checkPeriod); + strategy.setMaxSlowDuration(maxSlowDuration); + strategy.setMaxTimeSinceLastAck(maxTimeSinceLastAck); + + return strategy; + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + PolicyEntry policy = new PolicyEntry(); + + strategy = createSlowConsumerStrategy(); + underTest = strategy; + + policy.setSlowConsumerStrategy(strategy); + policy.setQueuePrefetch(10); + policy.setTopicPrefetch(10); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + return broker; + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.getPrefetchPolicy().setAll(1); + return factory; + } + + @Override + @Test + public void testSlowConsumerIsAbortedViaJmx() throws Exception { + strategy.setMaxTimeSinceLastAck(500); // so jmx does the abort + super.testSlowConsumerIsAbortedViaJmx(); + } + + @Test + public void testZeroPrefetchConsumerIsAborted() throws Exception { + strategy.setMaxTimeSinceLastAck(2000); // Make it shorter + + ActiveMQConnection conn = (ActiveMQConnection) createConnectionFactory().createConnection(); + conn.setExceptionListener(this); + connections.add(conn); + + Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageConsumer consumer = sess.createConsumer(destination); + assertNotNull(consumer); + conn.start(); + startProducers(destination, 20); + + Message message = consumer.receive(5000); + assertNotNull(message); + + TimeUnit.SECONDS.sleep(15); + + try { + consumer.receive(5000); + fail("Slow consumer not aborted."); + } catch (Exception ex) { + } + } + + @Test + public void testIdleConsumerCanBeAbortedNoMessages() throws Exception { + strategy.setIgnoreIdleConsumers(false); + strategy.setMaxTimeSinceLastAck(2000); // Make it shorter + + ActiveMQConnection conn = (ActiveMQConnection) createConnectionFactory().createConnection(); + conn.setExceptionListener(this); + connections.add(conn); + + Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageConsumer consumer = sess.createConsumer(destination); + assertNotNull(consumer); + conn.start(); + + startProducers(destination, 1); + + Message message = consumer.receive(5000); + assertNotNull(message); + + // Consumer needs to be closed before the reeive call. + TimeUnit.SECONDS.sleep(15); + + try { + consumer.receive(5000); + fail("Idle consumer not aborted."); + } catch (Exception ex) { + } + } + + @Test + public void testIdleConsumerCanBeAborted() throws Exception { + strategy.setIgnoreIdleConsumers(false); + strategy.setMaxTimeSinceLastAck(2000); // Make it shorter + + ActiveMQConnection conn = (ActiveMQConnection) createConnectionFactory().createConnection(); + conn.setExceptionListener(this); + connections.add(conn); + + Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageConsumer consumer = sess.createConsumer(destination); + assertNotNull(consumer); + conn.start(); + startProducers(destination, 1); + + Message message = consumer.receive(5000); + assertNotNull(message); + message.acknowledge(); + + // Consumer needs to be closed before the reeive call. + TimeUnit.SECONDS.sleep(15); + + try { + consumer.receive(5000); + fail("Idle consumer not aborted."); + } catch (Exception ex) { + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer1Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer1Test.java new file mode 100644 index 0000000000..6d3e970c78 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer1Test.java @@ -0,0 +1,71 @@ +/** + * 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.broker.policy; + +import javax.jms.ConnectionFactory; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.AbortSlowAckConsumerStrategy; +import org.apache.activemq.broker.region.policy.AbortSlowConsumerStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(value = Parameterized.class) +public class AbortSlowAckConsumer1Test extends AbortSlowConsumer1Test { + + protected long maxTimeSinceLastAck = 5 * 1000; + + public AbortSlowAckConsumer1Test(Boolean abortConnection, Boolean topic) { + super(abortConnection, topic); + } + + @Override + protected AbortSlowConsumerStrategy createSlowConsumerStrategy() { + return new AbortSlowConsumerStrategy(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + PolicyEntry policy = new PolicyEntry(); + + AbortSlowAckConsumerStrategy strategy = new AbortSlowAckConsumerStrategy(); + strategy.setAbortConnection(abortConnection); + strategy.setCheckPeriod(checkPeriod); + strategy.setMaxSlowDuration(maxSlowDuration); + strategy.setMaxTimeSinceLastAck(maxTimeSinceLastAck); + + policy.setSlowConsumerStrategy(strategy); + policy.setQueuePrefetch(10); + policy.setTopicPrefetch(10); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + return broker; + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.getPrefetchPolicy().setAll(1); + return factory; + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer2Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer2Test.java new file mode 100644 index 0000000000..948613e0c8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowAckConsumer2Test.java @@ -0,0 +1,71 @@ +/** + * 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.broker.policy; + +import javax.jms.ConnectionFactory; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.AbortSlowAckConsumerStrategy; +import org.apache.activemq.broker.region.policy.AbortSlowConsumerStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(value = Parameterized.class) +public class AbortSlowAckConsumer2Test extends AbortSlowConsumer2Test { + + protected long maxTimeSinceLastAck = 5 * 1000; + + public AbortSlowAckConsumer2Test(Boolean topic) { + super(topic); + } + + @Override + protected AbortSlowConsumerStrategy createSlowConsumerStrategy() { + return new AbortSlowConsumerStrategy(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + PolicyEntry policy = new PolicyEntry(); + + AbortSlowAckConsumerStrategy strategy = new AbortSlowAckConsumerStrategy(); + strategy.setAbortConnection(abortConnection); + strategy.setCheckPeriod(checkPeriod); + strategy.setMaxSlowDuration(maxSlowDuration); + strategy.setMaxTimeSinceLastAck(maxTimeSinceLastAck); + + policy.setSlowConsumerStrategy(strategy); + policy.setQueuePrefetch(10); + policy.setTopicPrefetch(10); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + return broker; + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.getPrefetchPolicy().setAll(1); + return factory; + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer0Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer0Test.java new file mode 100644 index 0000000000..9f2344350d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer0Test.java @@ -0,0 +1,244 @@ +/** + * 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.broker.policy; + +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQMessageConsumer; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.jmx.AbortSlowConsumerStrategyViewMBean; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.SocketProxy; +import org.apache.activemq.util.Wait; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.*; + + +@RunWith(value = Parameterized.class) +public class AbortSlowConsumer0Test extends AbortSlowConsumerBase { + + private static final Logger LOG = LoggerFactory.getLogger(AbortSlowConsumer0Test.class); + + @Parameterized.Parameters(name = "isTopic({0})") + public static Collection getTestParameters() { + return Arrays.asList(new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}}); + } + + public AbortSlowConsumer0Test(Boolean isTopic) { + this.topic = isTopic; + } + + @Test + public void testRegularConsumerIsNotAborted() throws Exception { + startConsumers(destination); + for (Connection c : connections) { + c.setExceptionListener(this); + } + startProducers(destination, 100); + allMessagesList.waitForMessagesToArrive(10); + allMessagesList.assertAtLeastMessagesReceived(10); + } + + @Test + public void testSlowConsumerIsAbortedViaJmx() throws Exception { + underTest.setMaxSlowDuration(60*1000); // so jmx does the abort + startConsumers(withPrefetch(2, destination)); + Entry consumertoAbort = consumers.entrySet().iterator().next(); + consumertoAbort.getValue().setProcessingDelay(8 * 1000); + for (Connection c : connections) { + c.setExceptionListener(this); + } + startProducers(destination, 100); + + consumertoAbort.getValue().assertMessagesReceived(1); + + ActiveMQDestination amqDest = (ActiveMQDestination)destination; + ObjectName destinationViewMBean = new ObjectName("org.apache.activemq:destinationType=" + + (amqDest.isTopic() ? "Topic" : "Queue") +",destinationName=" + + amqDest.getPhysicalName() + ",type=Broker,brokerName=localhost"); + + DestinationViewMBean queue = (DestinationViewMBean) broker.getManagementContext().newProxyInstance(destinationViewMBean, DestinationViewMBean.class, true); + ObjectName slowConsumerPolicyMBeanName = queue.getSlowConsumerStrategy(); + + assertNotNull(slowConsumerPolicyMBeanName); + + AbortSlowConsumerStrategyViewMBean abortPolicy = (AbortSlowConsumerStrategyViewMBean) + broker.getManagementContext().newProxyInstance(slowConsumerPolicyMBeanName, AbortSlowConsumerStrategyViewMBean.class, true); + + TimeUnit.SECONDS.sleep(3); + + TabularData slowOnes = abortPolicy.getSlowConsumers(); + assertEquals("one slow consumers", 1, slowOnes.size()); + + LOG.info("slow ones:" + slowOnes); + + CompositeData slowOne = (CompositeData) slowOnes.values().iterator().next(); + LOG.info("Slow one: " + slowOne); + + assertTrue("we have an object name", slowOne.get("subscription") instanceof ObjectName); + abortPolicy.abortConsumer((ObjectName)slowOne.get("subscription")); + + consumertoAbort.getValue().assertAtMostMessagesReceived(1); + + slowOnes = abortPolicy.getSlowConsumers(); + assertEquals("no slow consumers left", 0, slowOnes.size()); + + // verify mbean gone with destination + broker.getAdminView().removeTopic(amqDest.getPhysicalName()); + + try { + abortPolicy.getSlowConsumers(); + fail("expect not found post destination removal"); + } catch(UndeclaredThrowableException expected) { + assertTrue("correct exception: " + expected.getCause(), + expected.getCause() instanceof InstanceNotFoundException); + } + } + + private Destination withPrefetch(int i, Destination destination) { + String destWithPrefetch = + ((ActiveMQDestination) destination).getPhysicalName() + "?consumer.prefetchSize=" + i; + return topic ? new ActiveMQTopic(destWithPrefetch) : new ActiveMQQueue(destWithPrefetch); + } + + @Test + public void testOnlyOneSlowConsumerIsAborted() throws Exception { + consumerCount = 10; + startConsumers(destination); + Entry consumertoAbort = consumers.entrySet().iterator().next(); + consumertoAbort.getValue().setProcessingDelay(8 * 1000); + for (Connection c : connections) { + c.setExceptionListener(this); + } + startProducers(destination, 100); + + allMessagesList.waitForMessagesToArrive(99); + allMessagesList.assertAtLeastMessagesReceived(99); + + consumertoAbort.getValue().assertMessagesReceived(1); + TimeUnit.SECONDS.sleep(5); + consumertoAbort.getValue().assertAtMostMessagesReceived(1); + } + + @Test + public void testAbortAlreadyClosingConsumers() throws Exception { + consumerCount = 1; + startConsumers(withPrefetch(2, destination)); + for (MessageIdList list : consumers.values()) { + list.setProcessingDelay(6 * 1000); + } + for (Connection c : connections) { + c.setExceptionListener(this); + } + startProducers(destination, 100); + allMessagesList.waitForMessagesToArrive(consumerCount); + + for (MessageConsumer consumer : consumers.keySet()) { + LOG.info("closing consumer: " + consumer); + /// will block waiting for on message till 6secs expire + consumer.close(); + } + } + + @Test + public void testAbortConsumerOnDeadConnection() throws Exception { + TransportConnector transportConnector = broker.addConnector("tcp://0.0.0.0:0"); + transportConnector.setBrokerService(broker); + transportConnector.setTaskRunnerFactory(broker.getTaskRunnerFactory()); + transportConnector.start(); + SocketProxy socketProxy = new SocketProxy(transportConnector.getPublishableConnectURI()); + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(socketProxy.getUrl()); + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setAll(4); + connectionFactory.setPrefetchPolicy(prefetchPolicy); + Connection c = connectionFactory.createConnection(); + connections.add(c); + c.start(); + Session session = c.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final ActiveMQMessageConsumer messageconsumer = (ActiveMQMessageConsumer) session.createConsumer(destination); + startProducers(destination, 10); + + messageconsumer.receive(4000).acknowledge(); + assertNotNull(messageconsumer.receive(4000)); + assertNotNull(messageconsumer.receive(4000)); + assertNotNull(messageconsumer.receive(4000)); + + // close control command won't get through + socketProxy.pause(); + + ActiveMQDestination amqDest = (ActiveMQDestination)destination; + ObjectName destinationViewMBean = new ObjectName("org.apache.activemq:destinationType=" + + (amqDest.isTopic() ? "Topic" : "Queue") +",destinationName=" + + amqDest.getPhysicalName() + ",type=Broker,brokerName=localhost"); + + final DestinationViewMBean destView = (DestinationViewMBean) broker.getManagementContext().newProxyInstance(destinationViewMBean, DestinationViewMBean.class, true); + + assertTrue("Consumer gone from broker view", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("DestView {} comsumerCount {}", destView, destView.getConsumerCount()); + return 0 == destView.getConsumerCount(); + } + })); + + socketProxy.goOn(); + + assertTrue("consumer was closed", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + boolean closed = false; + try { + messageconsumer.receive(400); + } catch (javax.jms.IllegalStateException expected) { + closed = expected.toString().contains("closed"); + } + return closed; + } + })); + } + + @Override + public void onException(JMSException exception) { + exceptions.add(exception); + exception.printStackTrace(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer1Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer1Test.java new file mode 100644 index 0000000000..e17b362cf6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer1Test.java @@ -0,0 +1,104 @@ +/** + * 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.broker.policy; + +import org.apache.activemq.util.MessageIdList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertTrue; + +@RunWith(value = Parameterized.class) +public class AbortSlowConsumer1Test extends AbortSlowConsumerBase { + + private static final Logger LOG = LoggerFactory.getLogger(AbortSlowConsumer1Test.class); + + @Parameterized.Parameters(name = "abortConnection({0})-isTopic({1})") + public static Collection getTestParameters() { + return Arrays.asList(new Object[][]{ + {Boolean.TRUE, Boolean.TRUE}, + {Boolean.TRUE, Boolean.FALSE}, + {Boolean.FALSE, Boolean.TRUE}, + {Boolean.FALSE, Boolean.FALSE}}); + } + + public AbortSlowConsumer1Test(Boolean abortConnection, Boolean topic) { + this.abortConnection = abortConnection; + this.topic = topic; + } + + @Test(timeout = 60 * 1000) + public void testSlowConsumerIsAborted() throws Exception { + startConsumers(destination); + Entry consumertoAbort = consumers.entrySet().iterator().next(); + consumertoAbort.getValue().setProcessingDelay(8 * 1000); + for (Connection c : connections) { + c.setExceptionListener(this); + } + startProducers(destination, 100); + + consumertoAbort.getValue().assertMessagesReceived(1); + TimeUnit.SECONDS.sleep(5); + consumertoAbort.getValue().assertAtMostMessagesReceived(1); + } + + @Test(timeout = 60 * 1000) + public void testAbortAlreadyClosedConsumers() throws Exception { + Connection conn = createConnectionFactory().createConnection(); + conn.setExceptionListener(this); + connections.add(conn); + + Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageConsumer consumer = sess.createConsumer(destination); + conn.start(); + startProducers(destination, 20); + TimeUnit.SECONDS.sleep(1); + LOG.info("closing consumer: " + consumer); + consumer.close(); + + TimeUnit.SECONDS.sleep(5); + assertTrue("no exceptions : " + exceptions.toArray(), exceptions.isEmpty()); + } + + @Test(timeout = 60 * 1000) + public void testAbortAlreadyClosedConnection() throws Exception { + Connection conn = createConnectionFactory().createConnection(); + conn.setExceptionListener(this); + + Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + sess.createConsumer(destination); + conn.start(); + startProducers(destination, 20); + TimeUnit.SECONDS.sleep(1); + LOG.info("closing connection: " + conn); + conn.close(); + + TimeUnit.SECONDS.sleep(5); + assertTrue("no exceptions : " + exceptions.toArray(), exceptions.isEmpty()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer2Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer2Test.java new file mode 100644 index 0000000000..72630278cc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumer2Test.java @@ -0,0 +1,53 @@ +/** + * 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.broker.policy; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map.Entry; +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import org.apache.activemq.util.MessageIdList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(value = Parameterized.class) +public class AbortSlowConsumer2Test extends AbortSlowConsumerBase { + + @Parameterized.Parameters(name = "isTopic({0})") + public static Collection getTestParameters() { + return Arrays.asList(new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}}); + } + + public AbortSlowConsumer2Test(Boolean isTopic) { + this.topic = isTopic; + } + + @Test(timeout = 60 * 1000) + public void testLittleSlowConsumerIsNotAborted() throws Exception { + startConsumers(destination); + Entry consumertoAbort = consumers.entrySet().iterator().next(); + consumertoAbort.getValue().setProcessingDelay(500); + for (Connection c : connections) { + c.setExceptionListener(this); + } + startProducers(destination, 12); + allMessagesList.waitForMessagesToArrive(10); + allMessagesList.assertAtLeastMessagesReceived(10); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumerBase.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumerBase.java new file mode 100644 index 0000000000..ee28112dbe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/AbortSlowConsumerBase.java @@ -0,0 +1,96 @@ +/** + * 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.broker.policy; + +import junit.framework.Test; +import org.apache.activemq.JmsMultipleClientsTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.AbortSlowConsumerStrategyViewMBean; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.broker.region.policy.AbortSlowConsumerStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.util.MessageIdList; +import org.junit.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + + +public class AbortSlowConsumerBase extends JmsMultipleClientsTestSupport implements ExceptionListener { + + private static final Logger LOG = LoggerFactory.getLogger(AbortSlowConsumerBase.class); + + protected AbortSlowConsumerStrategy underTest; + protected boolean abortConnection = false; + protected long checkPeriod = 2 * 1000; + protected long maxSlowDuration = 5 * 1000; + protected final List exceptions = new ArrayList(); + + @Override + @Before + public void setUp() throws Exception { + exceptions.clear(); + topic = true; + underTest = createSlowConsumerStrategy(); + super.setUp(); + createDestination(); + } + + protected AbortSlowConsumerStrategy createSlowConsumerStrategy() { + return new AbortSlowConsumerStrategy(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + PolicyEntry policy = new PolicyEntry(); + underTest.setAbortConnection(abortConnection); + underTest.setCheckPeriod(checkPeriod); + underTest.setMaxSlowDuration(maxSlowDuration); + + policy.setSlowConsumerStrategy(underTest); + policy.setQueuePrefetch(10); + policy.setTopicPrefetch(10); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + return broker; + } + + @Override + public void onException(JMSException exception) { + exceptions.add(exception); + exception.printStackTrace(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DeadLetterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DeadLetterTest.java new file mode 100644 index 0000000000..6c31237759 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DeadLetterTest.java @@ -0,0 +1,94 @@ +/** + * 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.broker.policy; + +import javax.jms.Destination; +import javax.jms.Message; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class DeadLetterTest extends DeadLetterTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(DeadLetterTest.class); + + protected int rollbackCount; + + protected void doTest() throws Exception { + connection.start(); + + ActiveMQConnection amqConnection = (ActiveMQConnection) connection; + rollbackCount = amqConnection.getRedeliveryPolicy().getMaximumRedeliveries() + 1; + LOG.info("Will redeliver messages: " + rollbackCount + " times"); + + makeConsumer(); + makeDlqConsumer(); + + sendMessages(); + + // now lets receive and rollback N times + for (int i = 0; i < messageCount; i++) { + consumeAndRollback(i); + } + + for (int i = 0; i < messageCount; i++) { + Message msg = dlqConsumer.receive(1000); + assertMessage(msg, i); + assertNotNull("Should be a DLQ message for loop: " + i, msg); + } + session.commit(); + } + + protected void consumeAndRollback(int messageCounter) throws Exception { + for (int i = 0; i < rollbackCount; i++) { + Message message = consumer.receive(5000); + assertNotNull("No message received for message: " + messageCounter + " and rollback loop: " + i, message); + assertMessage(message, messageCounter); + + session.rollback(); + } + LOG.info("Rolled back: " + rollbackCount + " times"); + } + + protected void setUp() throws Exception { + transactedMode = true; + super.setUp(); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory answer = super.createConnectionFactory(); + RedeliveryPolicy policy = new RedeliveryPolicy(); + policy.setMaximumRedeliveries(3); + policy.setBackOffMultiplier((short) 1); + policy.setInitialRedeliveryDelay(10); + policy.setUseExponentialBackOff(false); + answer.setRedeliveryPolicy(policy); + return answer; + } + + protected Destination createDlqDestination() { + return new ActiveMQQueue("ActiveMQ.DLQ"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DeadLetterTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DeadLetterTestSupport.java new file mode 100644 index 0000000000..b275f2ea39 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DeadLetterTestSupport.java @@ -0,0 +1,211 @@ +/** + * 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.broker.policy; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public abstract class DeadLetterTestSupport extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(DeadLetterTestSupport.class); + + protected int messageCount = 10; + protected long timeToLive; + protected Connection connection; + protected Session session; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected boolean durableSubscriber; + protected Destination dlqDestination; + protected MessageConsumer dlqConsumer; + protected QueueBrowser dlqBrowser; + protected BrokerService broker; + protected boolean transactedMode; + protected int acknowledgeMode = Session.CLIENT_ACKNOWLEDGE; + private Destination destination; + + protected void setUp() throws Exception { + super.setUp(); + broker = createBroker(); + broker.start(); + connection = createConnection(); + connection.setClientID(createClientId()); + + session = connection.createSession(transactedMode, acknowledgeMode); + connection.start(); + } + + protected String createClientId() { + return toString(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + if (broker != null) { + broker.stop(); + } + } + + protected abstract void doTest() throws Exception; + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + PolicyEntry policy = new PolicyEntry(); + DeadLetterStrategy defaultDeadLetterStrategy = policy.getDeadLetterStrategy(); + if(defaultDeadLetterStrategy!=null) { + defaultDeadLetterStrategy.setProcessNonPersistent(true); + } + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + return broker; + } + + protected void makeConsumer() throws JMSException { + Destination destination = getDestination(); + LOG.info("Consuming from: " + destination); + if (durableSubscriber) { + consumer = session.createDurableSubscriber((Topic)destination, destination.toString()); + } else { + consumer = session.createConsumer(destination); + } + } + + protected void makeDlqConsumer() throws Exception { + dlqDestination = createDlqDestination(); + + LOG.info("Consuming from dead letter on: " + dlqDestination); + dlqConsumer = session.createConsumer(dlqDestination); + } + + protected void makeDlqBrowser() throws JMSException { + dlqDestination = createDlqDestination(); + + LOG.info("Browsing dead letter on: " + dlqDestination); + dlqBrowser = session.createBrowser((Queue)dlqDestination); + } + + protected void sendMessages() throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(getDestination()); + producer.setDeliveryMode(deliveryMode); + producer.setTimeToLive(timeToLive); + + LOG.info("Sending " + messageCount + " messages to: " + getDestination()); + for (int i = 0; i < messageCount; i++) { + Message message = createMessage(session, i); + producer.send(message); + } + } + + protected TextMessage createMessage(Session session, int i) throws JMSException { + return session.createTextMessage(getMessageText(i)); + } + + protected String getMessageText(int i) { + return "message: " + i; + } + + protected void assertMessage(Message message, int i) throws Exception { + LOG.info("Received message: " + message); + assertNotNull("No message received for index: " + i, message); + assertTrue("Should be a TextMessage not: " + message, message instanceof TextMessage); + TextMessage textMessage = (TextMessage)message; + assertEquals("text of message: " + i, getMessageText(i), textMessage.getText()); + } + + protected abstract Destination createDlqDestination(); + + public void testTransientTopicMessage() throws Exception { + super.topic = true; + deliveryMode = DeliveryMode.NON_PERSISTENT; + durableSubscriber = true; + doTest(); + } + + public void testDurableTopicMessage() throws Exception { + super.topic = true; + deliveryMode = DeliveryMode.PERSISTENT; + durableSubscriber = true; + doTest(); + } + + public void testTransientQueueMessage() throws Exception { + super.topic = false; + deliveryMode = DeliveryMode.NON_PERSISTENT; + durableSubscriber = false; + doTest(); + validateConsumerPrefetch(this.getDestinationString(), 0); + } + + public void testDurableQueueMessage() throws Exception { + super.topic = false; + deliveryMode = DeliveryMode.PERSISTENT; + durableSubscriber = false; + doTest(); + validateConsumerPrefetch(this.getDestinationString(), 0); + } + + public Destination getDestination() { + if (destination == null) { + destination = createDestination(); + } + return destination; + } + + private void validateConsumerPrefetch(String destination, long expectedCount) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + for (org.apache.activemq.broker.region.Destination dest : regionBroker.getQueueRegion().getDestinationMap().values()) { + if (dest.getName().equals(destination)) { + DestinationStatistics stats = dest.getDestinationStatistics(); + LOG.info(">>>> inflight for : " + dest.getName() + ": " + stats.getInflight().getCount()); + assertEquals("inflight for: " + dest.getName() + ": " + stats.getInflight().getCount() + " matches", + expectedCount, stats.getInflight().getCount()); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DestinationCursorConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DestinationCursorConfigTest.java new file mode 100644 index 0000000000..a5f7984b38 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DestinationCursorConfigTest.java @@ -0,0 +1,74 @@ +/** + * 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.broker.policy; + +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PendingSubscriberMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.VMPendingSubscriberMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.springframework.core.io.ClassPathResource; + +/** + * + */ +public class DestinationCursorConfigTest extends TestSupport { + protected BrokerService broker; + + @Override + protected void setUp() throws Exception { + broker = createBroker(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + super.tearDown(); + } + + protected BrokerService createBroker() throws Exception { + BrokerFactoryBean factory = new BrokerFactoryBean(new ClassPathResource("org/apache/activemq/broker/policy/cursor.xml")); + factory.afterPropertiesSet(); + BrokerService answer = factory.getBroker(); + return answer; + } + + public void testQueueConfiguration() throws Exception { + super.topic = false; + ActiveMQDestination destination = (ActiveMQDestination) createDestination("org.apache.foo"); + PolicyEntry entry = broker.getDestinationPolicy().getEntryFor(destination); + PendingQueueMessageStoragePolicy policy = entry.getPendingQueuePolicy(); + assertNotNull(policy); + assertTrue("Policy is: " + policy, policy instanceof VMPendingQueueMessageStoragePolicy); + } + + public void testTopicConfiguration() throws Exception { + super.topic = true; + ActiveMQDestination destination = (ActiveMQDestination) createDestination("org.apache.foo"); + PolicyEntry entry = broker.getDestinationPolicy().getEntryFor(destination); + PendingSubscriberMessageStoragePolicy policy = entry.getPendingSubscriberPolicy(); + assertNotNull(policy); + assertFalse(entry.isProducerFlowControl()); + assertTrue(entry.getMemoryLimit()==(1024*1024)); + assertTrue("subscriberPolicy is: " + policy, policy instanceof VMPendingSubscriberMessageStoragePolicy); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DiscardingDeadLetterPolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DiscardingDeadLetterPolicyTest.java new file mode 100644 index 0000000000..f43f886088 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/DiscardingDeadLetterPolicyTest.java @@ -0,0 +1,77 @@ +/** + * 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.broker.policy; + +import javax.jms.Message; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.DiscardingDeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class DiscardingDeadLetterPolicyTest extends DeadLetterTest { + private static final Logger LOG = LoggerFactory.getLogger(DiscardingDeadLetterPolicyTest.class); + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + + PolicyEntry policy = new PolicyEntry(); + DeadLetterStrategy strategy = new DiscardingDeadLetterStrategy(); + strategy.setProcessNonPersistent(true); + policy.setDeadLetterStrategy(strategy); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + return broker; + } + + @Override + protected void doTest() throws Exception { + connection.start(); + + ActiveMQConnection amqConnection = (ActiveMQConnection) connection; + rollbackCount = amqConnection.getRedeliveryPolicy().getMaximumRedeliveries() + 1; + LOG.info("Will redeliver messages: " + rollbackCount + " times"); + + makeConsumer(); + makeDlqConsumer(); + + sendMessages(); + + // now lets receive and rollback N times + for (int i = 0; i < messageCount; i++) { + consumeAndRollback(i); + } + + for (int i = 0; i < messageCount; i++) { + Message msg = dlqConsumer.receive(1000); + assertNull("Should not be a DLQ message for loop: " + i, msg); + } + session.commit(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/IndividualDeadLetterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/IndividualDeadLetterTest.java new file mode 100644 index 0000000000..a587be89d4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/IndividualDeadLetterTest.java @@ -0,0 +1,109 @@ +/** + * 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.broker.policy; + +import java.util.Enumeration; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.IndividualDeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class IndividualDeadLetterTest extends DeadLetterTest { + private static final Logger LOG = LoggerFactory.getLogger(IndividualDeadLetterTest.class); + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + + PolicyEntry policy = new PolicyEntry(); + DeadLetterStrategy strategy = new IndividualDeadLetterStrategy(); + strategy.setProcessNonPersistent(true); + policy.setDeadLetterStrategy(strategy); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + return broker; + } + + @Override + protected Destination createDlqDestination() { + String prefix = topic ? "ActiveMQ.DLQ.Topic." : "ActiveMQ.DLQ.Queue."; + return new ActiveMQQueue(prefix + getClass().getName() + "." + getName()); + } + + public void testDLQBrowsing() throws Exception { + super.topic = false; + deliveryMode = DeliveryMode.PERSISTENT; + durableSubscriber = false; + messageCount = 1; + + connection.start(); + + ActiveMQConnection amqConnection = (ActiveMQConnection) connection; + rollbackCount = amqConnection.getRedeliveryPolicy().getMaximumRedeliveries() + 1; + LOG.info("Will redeliver messages: " + rollbackCount + " times"); + + sendMessages(); + + // now lets receive and rollback N times + for (int i = 0; i < rollbackCount; i++) { + makeConsumer(); + Message message = consumer.receive(5000); + assertNotNull("No message received: ", message); + + session.rollback(); + LOG.info("Rolled back: " + rollbackCount + " times"); + consumer.close(); + } + + makeDlqBrowser(); + browseDlq(); + dlqBrowser.close(); + session.close(); + Thread.sleep(1000); + session = connection.createSession(transactedMode, acknowledgeMode); + Queue testQueue = new ActiveMQQueue("ActiveMQ.DLQ.Queue.ActiveMQ.DLQ.Queue." + getClass().getName() + "." + getName()); + MessageConsumer testConsumer = session.createConsumer(testQueue); + assertNull("The message shouldn't be sent to another DLQ", testConsumer.receive(1000)); + + } + + protected void browseDlq() throws Exception { + Enumeration messages = dlqBrowser.getEnumeration(); + while (messages.hasMoreElements()) { + LOG.info("Browsing: " + messages.nextElement()); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/IndividualDeadLetterViaXmlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/IndividualDeadLetterViaXmlTest.java new file mode 100644 index 0000000000..6dd87c2c38 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/IndividualDeadLetterViaXmlTest.java @@ -0,0 +1,48 @@ +/** + * 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.broker.policy; + +import javax.jms.Destination; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * + * + */ +public class IndividualDeadLetterViaXmlTest extends DeadLetterTest { + private static final Logger LOG = LoggerFactory.getLogger(IndividualDeadLetterViaXmlTest.class); + + + protected BrokerService createBroker() throws Exception { + BrokerFactoryBean factory = new BrokerFactoryBean(new ClassPathResource("org/apache/activemq/broker/policy/individual-dlq.xml")); + factory.afterPropertiesSet(); + BrokerService answer = factory.getBroker(); + return answer; + } + + protected Destination createDlqDestination() { + String queueName = "Test.DLQ." + getClass().getName() + "." + getName(); + LOG.info("Using queue name: " + queueName); + return new ActiveMQQueue(queueName); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/MessageGroupConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/MessageGroupConfigTest.java new file mode 100644 index 0000000000..112cc463db --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/MessageGroupConfigTest.java @@ -0,0 +1,93 @@ +/** + * 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.broker.policy; + +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.broker.region.group.CachedMessageGroupMap; +import org.apache.activemq.broker.region.group.MessageGroupHashBucket; +import org.apache.activemq.broker.region.group.MessageGroupMap; +import org.apache.activemq.broker.region.group.SimpleMessageGroupMap; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; + +/** + * + */ +public class MessageGroupConfigTest extends TestSupport { + protected BrokerService broker; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + super.tearDown(); + } + + + + public void testCachedGroupConfiguration() throws Exception { + doTestGroupConfiguration("cached",CachedMessageGroupMap.class); + } + + public void testCachedGroupConfigurationWithCacheSize() throws Exception { + CachedMessageGroupMap result = (CachedMessageGroupMap) doTestGroupConfiguration("cached?cacheSize=10",CachedMessageGroupMap.class); + assertEquals(10,result.getMaximumCacheSize()); + + } + + public void testSimpleGroupConfiguration() throws Exception { + doTestGroupConfiguration("simple", SimpleMessageGroupMap.class); + } + + public void testBucketGroupConfiguration() throws Exception { + doTestGroupConfiguration("bucket", MessageGroupHashBucket.class); + } + + public void testBucketGroupConfigurationWithBucketCount() throws Exception { + MessageGroupHashBucket result = (MessageGroupHashBucket) doTestGroupConfiguration("bucket?bucketCount=2", MessageGroupHashBucket.class); + assertEquals(2,result.getBucketCount()); + } + + public MessageGroupMap doTestGroupConfiguration(String type, Class classType) throws Exception { + broker = new BrokerService(); + + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setMessageGroupMapFactoryType(type); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + broker.start(); + super.topic = false; + ActiveMQDestination destination = (ActiveMQDestination) createDestination("org.apache.foo"); + Queue brokerDestination = (Queue) broker.getDestination(destination); + + assertNotNull(brokerDestination); + MessageGroupMap messageGroupMap = brokerDestination.getMessageGroupOwners(); + assertNotNull(messageGroupMap); + assertTrue(messageGroupMap.getClass().isAssignableFrom(classType)); + return messageGroupMap; + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/MessageListenerDeadLetterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/MessageListenerDeadLetterTest.java new file mode 100644 index 0000000000..b91f5a8b84 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/MessageListenerDeadLetterTest.java @@ -0,0 +1,151 @@ +/** + * 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.broker.policy; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageListenerDeadLetterTest extends DeadLetterTestSupport { + private static final Logger LOG = LoggerFactory + .getLogger(MessageListenerDeadLetterTest.class); + + private int rollbackCount; + + private Session dlqSession; + + private final Error[] error = new Error[1]; + + protected void doTest() throws Exception { + messageCount = 200; + connection.start(); + + ActiveMQConnection amqConnection = (ActiveMQConnection) connection; + rollbackCount = amqConnection.getRedeliveryPolicy().getMaximumRedeliveries() + 1; + LOG.info("Will redeliver messages: " + rollbackCount + " times"); + + makeConsumer(); + makeDlqConsumer(); + + sendMessages(); + + // now lets receive and rollback N times + int maxRollbacks = messageCount * rollbackCount; + consumer.setMessageListener(new RollbackMessageListener(maxRollbacks, rollbackCount)); + + for (int i = 0; i < messageCount; i++) { + Message msg = dlqConsumer.receive(4000); + if (error[0] != null) { + // error from message listener + throw error[0]; + } + assertMessage(msg, i); + assertNotNull("Should be a DLQ message for loop: " + i, msg); + } + if (error[0] != null) { + throw error[0]; + } + } + + protected void makeDlqConsumer() throws JMSException { + dlqDestination = createDlqDestination(); + + LOG.info("Consuming from dead letter on: " + dlqDestination); + dlqConsumer = dlqSession.createConsumer(dlqDestination); + } + + @Override + protected void setUp() throws Exception { + transactedMode = true; + super.setUp(); + dlqSession = connection.createSession(transactedMode, acknowledgeMode); + } + + @Override + protected void tearDown() throws Exception { + dlqConsumer.close(); + dlqSession.close(); + session.close(); + super.tearDown(); + }; + + protected ActiveMQConnectionFactory createConnectionFactory() + throws Exception { + ActiveMQConnectionFactory answer = super.createConnectionFactory(); + RedeliveryPolicy policy = new RedeliveryPolicy(); + policy.setMaximumRedeliveries(3); + policy.setBackOffMultiplier((short) 1); + policy.setRedeliveryDelay(0); + policy.setInitialRedeliveryDelay(0); + policy.setUseExponentialBackOff(false); + answer.setRedeliveryPolicy(policy); + return answer; + } + + protected Destination createDlqDestination() { + return new ActiveMQQueue("ActiveMQ.DLQ"); + } + + class RollbackMessageListener implements MessageListener { + + final int maxRollbacks; + + final int deliveryCount; + + AtomicInteger rollbacks = new AtomicInteger(); + + RollbackMessageListener(int c, int delvery) { + maxRollbacks = c; + deliveryCount = delvery; + } + + public void onMessage(Message message) { + try { + int expectedMessageId = rollbacks.get() / deliveryCount; + LOG.info("expecting messageId: " + expectedMessageId); + assertMessage(message, expectedMessageId); + if (rollbacks.incrementAndGet() > maxRollbacks) { + fail("received too many messages, already done too many rollbacks: " + + rollbacks); + } + session.rollback(); + + } catch (Throwable e) { + LOG.error("unexpected exception:" + e, e); + // propagating assertError to execution task will cause a hang + // at shutdown + if (e instanceof Error) { + error[0] = (Error) e; + } else { + fail("unexpected exception: " + e); + } + + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/NoConsumerDeadLetterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/NoConsumerDeadLetterTest.java new file mode 100644 index 0000000000..7c5373099f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/NoConsumerDeadLetterTest.java @@ -0,0 +1,112 @@ +/** + * 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.broker.policy; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; + +/** + * + */ +public class NoConsumerDeadLetterTest extends DeadLetterTestSupport { + + // lets disable the inapplicable tests + public void testDurableQueueMessage() throws Exception { + } + + public void testDurableTopicMessage() throws Exception { + } + + protected void doTest() throws Exception { + makeDlqConsumer(); + sendMessages(); + + for (int i = 0; i < messageCount; i++) { + Message msg = dlqConsumer.receive(1000); + assertNotNull("Should be a message for loop: " + i, msg); + } + } + + public void testConsumerReceivesMessages() throws Exception { + this.topic = false; + ActiveMQConnectionFactory factory = (ActiveMQConnectionFactory)createConnectionFactory(); + connection = (ActiveMQConnection)factory.createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(getDestination()); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + Topic advisoryTopic = AdvisorySupport.getNoQueueConsumersAdvisoryTopic(getDestination()); + MessageConsumer advisoryConsumer = session.createConsumer(advisoryTopic); + + TextMessage msg = session.createTextMessage("Message: x"); + producer.send(msg); + + Message advisoryMessage = advisoryConsumer.receive(1000); + assertNotNull("Advisory message not received", advisoryMessage); + + Thread.sleep(1000); + + factory = (ActiveMQConnectionFactory)createConnectionFactory(); + connection = (ActiveMQConnection)factory.createConnection(); + connection.start(); + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = session.createConsumer(getDestination()); + Message received = consumer.receive(1000); + assertNotNull("Message not received", received); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + + PolicyEntry policy = new PolicyEntry(); + policy.setSendAdvisoryIfNoConsumers(true); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + return broker; + } + + protected Destination createDlqDestination() { + if (this.topic) { + return AdvisorySupport.getNoTopicConsumersAdvisoryTopic((ActiveMQDestination)getDestination()); + } else { + return AdvisorySupport.getNoQueueConsumersAdvisoryTopic((ActiveMQDestination)getDestination()); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/NoRetryDeadLetterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/NoRetryDeadLetterTest.java new file mode 100644 index 0000000000..a14df74b7d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/NoRetryDeadLetterTest.java @@ -0,0 +1,33 @@ +/** + * 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.broker.policy; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; + +public class NoRetryDeadLetterTest extends DeadLetterTest { + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory connectionFactory = super.createConnectionFactory(); + RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); + redeliveryPolicy.setMaximumRedeliveries(0); + connectionFactory.setRedeliveryPolicy(redeliveryPolicy); + return connectionFactory; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/PerDurableConsumerDeadLetterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/PerDurableConsumerDeadLetterTest.java new file mode 100644 index 0000000000..05be639562 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/PerDurableConsumerDeadLetterTest.java @@ -0,0 +1,70 @@ +/** + * 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.broker.policy; + +import javax.jms.Destination; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.IndividualDeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; + +/** + * for durable subs, allow a dlq per subscriber such that poison messages are not duplicates + * on the dlq and such that rejecting consumers can be identified + * https://issues.apache.org/jira/browse/AMQ-3003 + */ +public class PerDurableConsumerDeadLetterTest extends DeadLetterTest { + + private static final String CLIENT_ID = "george"; + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + + PolicyEntry policy = new PolicyEntry(); + IndividualDeadLetterStrategy strategy = new IndividualDeadLetterStrategy(); + strategy.setProcessNonPersistent(true); + strategy.setDestinationPerDurableSubscriber(true); + policy.setDeadLetterStrategy(strategy); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + return broker; + } + + @Override + protected String createClientId() { + return CLIENT_ID; + } + + @Override + protected Destination createDlqDestination() { + String prefix = topic ? "ActiveMQ.DLQ.Topic." : "ActiveMQ.DLQ.Queue."; + String destinationName = prefix + getClass().getName() + "." + getName(); + if (durableSubscriber) { + String subName = // connectionId:SubName + CLIENT_ID + ":" + getDestination().toString(); + destinationName += "." + subName ; + } + return new ActiveMQQueue(destinationName); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/PriorityNetworkDispatchPolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/PriorityNetworkDispatchPolicyTest.java new file mode 100644 index 0000000000..448f47c349 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/PriorityNetworkDispatchPolicyTest.java @@ -0,0 +1,81 @@ +/** + * 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.broker.policy; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.region.Subscription; +import org.apache.activemq.broker.region.TopicSubscription; +import org.apache.activemq.broker.region.policy.PriorityNetworkDispatchPolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.usage.SystemUsage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PriorityNetworkDispatchPolicyTest { + + PriorityNetworkDispatchPolicy underTest = new PriorityNetworkDispatchPolicy(); + SystemUsage usageManager = new SystemUsage(); + ConsumerInfo info = new ConsumerInfo(); + ActiveMQMessage node = new ActiveMQMessage(); + ConsumerId id = new ConsumerId(); + ConnectionContext context = new ConnectionContext(); + BrokerService brokerService = new BrokerService(); + + @Before + public void init() throws Exception { + info.setDestination(ActiveMQDestination.createDestination("test", ActiveMQDestination.TOPIC_TYPE)); + info.setConsumerId(id); + info.setNetworkSubscription(true); + info.setNetworkConsumerPath(new ConsumerId[]{id}); + node.setMessageId(new MessageId("test:1:1:1:1")); + } + + @After + public void stopBroker() throws Exception { + brokerService.stop(); + } + + @Test + public void testRemoveLowerPriorityDup() throws Exception { + + List consumers = new ArrayList(); + + for (int i=0; i<3; i++) { + ConsumerInfo instance = info.copy(); + instance.setPriority((byte)i); + consumers.add(new TopicSubscription(brokerService.getBroker(), context, instance, usageManager)); + } + underTest.dispatch(node, null, consumers); + + long count = 0; + for (Subscription consumer : consumers) { + count += consumer.getEnqueueCounter(); + } + assertEquals("only one sub got message", 1, count); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/RoundRobinDispatchPolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/RoundRobinDispatchPolicyTest.java new file mode 100644 index 0000000000..221f603e8b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/RoundRobinDispatchPolicyTest.java @@ -0,0 +1,125 @@ +/** + * 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.broker.policy; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.QueueSubscriptionTest; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.RoundRobinDispatchPolicy; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +@RunWith(BlockJUnit4ClassRunner.class) +public class RoundRobinDispatchPolicyTest extends QueueSubscriptionTest { + + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + + PolicyEntry policy = new PolicyEntry(); + policy.setDispatchPolicy(new RoundRobinDispatchPolicy()); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + return broker; + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersSmallMessagesOnePrefetch() throws Exception { + super.testOneProducerTwoConsumersSmallMessagesOnePrefetch(); + + // Ensure that each consumer should have received at least one message + // We cannot guarantee that messages will be equally divided, since + // prefetch is one + assertEachConsumerReceivedAtLeastXMessages(1); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersSmallMessagesLargePrefetch() throws Exception { + super.testOneProducerTwoConsumersSmallMessagesLargePrefetch(); + assertMessagesDividedAmongConsumers(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersLargeMessagesOnePrefetch() throws Exception { + super.testOneProducerTwoConsumersLargeMessagesOnePrefetch(); + + // Ensure that each consumer should have received at least one message + // We cannot guarantee that messages will be equally divided, since + // prefetch is one + assertEachConsumerReceivedAtLeastXMessages(1); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersLargeMessagesLargePrefetch() throws Exception { + super.testOneProducerTwoConsumersLargeMessagesLargePrefetch(); + assertMessagesDividedAmongConsumers(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerManyConsumersFewMessages() throws Exception { + super.testOneProducerManyConsumersFewMessages(); + + // Since there are more consumers, each consumer should have received at + // most one message only + assertMessagesDividedAmongConsumers(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerManyConsumersManyMessages() throws Exception { + super.testOneProducerManyConsumersManyMessages(); + assertMessagesDividedAmongConsumers(); + } + + @Test(timeout = 60 * 1000) + public void testManyProducersManyConsumers() throws Exception { + super.testManyProducersManyConsumers(); + assertMessagesDividedAmongConsumers(); + } + + @Test(timeout = 60 * 1000) + public void testOneProducerTwoMatchingConsumersOneNotMatchingConsumer() throws Exception { + // Create consumer that won't consume any message + createMessageConsumer(createConnectionFactory().createConnection(), createDestination(), "JMSPriority<1"); + super.testOneProducerTwoConsumersSmallMessagesLargePrefetch(); + assertMessagesDividedAmongConsumers(); + } + + protected MessageConsumer createMessageConsumer(Connection conn, Destination dest, String selector) throws Exception { + connections.add(conn); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = sess.createConsumer(dest, selector); + conn.start(); + + return consumer; + } + + public void assertMessagesDividedAmongConsumers() { + assertEachConsumerReceivedAtLeastXMessages((messageCount * producerCount) / consumerCount); + assertEachConsumerReceivedAtMostXMessages(((messageCount * producerCount) / consumerCount) + 1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/SecureDLQTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/SecureDLQTest.java new file mode 100644 index 0000000000..354031ed9c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/SecureDLQTest.java @@ -0,0 +1,128 @@ +/** + * 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.broker.policy; + +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.filter.DestinationMap; +import org.apache.activemq.security.*; + +import javax.jms.*; + +import static org.apache.activemq.security.SimpleSecurityBrokerSystemTest.*; + +public class SecureDLQTest extends DeadLetterTestSupport { + + Connection dlqConnection; + Session dlqSession; + + public static AuthorizationMap createAuthorizationMap() { + DestinationMap readAccess = new DefaultAuthorizationMap(); + readAccess.put(new ActiveMQQueue("TEST"), ADMINS); + readAccess.put(new ActiveMQQueue("TEST"), USERS); + readAccess.put(new ActiveMQQueue("ActiveMQ.DLQ"), ADMINS); + + DestinationMap writeAccess = new DefaultAuthorizationMap(); + writeAccess.put(new ActiveMQQueue("TEST"), ADMINS); + writeAccess.put(new ActiveMQQueue("TEST"), USERS); + writeAccess.put(new ActiveMQQueue("ActiveMQ.DLQ"), ADMINS); + + readAccess.put(new ActiveMQTopic("ActiveMQ.Advisory.>"), WILDCARD); + writeAccess.put(new ActiveMQTopic("ActiveMQ.Advisory.>"), WILDCARD); + + DestinationMap adminAccess = new DefaultAuthorizationMap(); + adminAccess.put(new ActiveMQQueue("TEST"), ADMINS); + adminAccess.put(new ActiveMQQueue("TEST"), USERS); + adminAccess.put(new ActiveMQQueue("ActiveMQ.DLQ"), ADMINS); + adminAccess.put(new ActiveMQTopic("ActiveMQ.Advisory.>"), WILDCARD); + + return new SimpleAuthorizationMap(writeAccess, readAccess, adminAccess); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + AuthorizationPlugin authorizationPlugin = new AuthorizationPlugin(createAuthorizationMap()); + + broker.setPlugins(new BrokerPlugin[] {authorizationPlugin, new SimpleSecurityBrokerSystemTest.SimpleAuthenticationFactory()}); + return broker; + } + + // lets disable the inapplicable tests + public void testTransientTopicMessage() throws Exception { + } + + public void testDurableTopicMessage() throws Exception { + } + + @Override + protected void doTest() throws Exception { + timeToLive = 1000; + acknowledgeMode = Session.CLIENT_ACKNOWLEDGE; + makeConsumer(); + sendMessages(); + Thread.sleep(1000); + consumer.close(); + + Thread.sleep(1000); + // this should try to send expired messages to dlq + makeConsumer(); + + makeDlqConsumer(); + for (int i = 0; i < messageCount; i++) { + Message msg = dlqConsumer.receive(1000); + assertMessage(msg, i); + assertNotNull("Should be a DLQ message for loop: " + i, msg); + } + + } + + @Override + public void tearDown() throws Exception { + if (dlqConnection != null) { + dlqConnection.close(); + } + super.tearDown(); + } + + @Override + protected Connection createConnection() throws Exception { + return getConnectionFactory().createConnection("user", "password"); + } + + @Override + protected void makeDlqConsumer() throws Exception { + dlqDestination = createDlqDestination(); + dlqConnection = getConnectionFactory().createConnection("system", "manager"); + dlqConnection.start(); + dlqSession = dlqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + dlqConsumer = dlqSession.createConsumer(dlqDestination); + } + + @Override + protected Destination createDlqDestination() { + return new ActiveMQQueue("ActiveMQ.DLQ"); + } + + @Override + protected String getDestinationString() { + return "TEST"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/SimpleDispatchPolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/SimpleDispatchPolicyTest.java new file mode 100644 index 0000000000..d6d6b08c6b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/SimpleDispatchPolicyTest.java @@ -0,0 +1,91 @@ +/** + * 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.broker.policy; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.QueueSubscriptionTest; +import org.apache.activemq.broker.region.policy.FixedCountSubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.SimpleDispatchPolicy; +import org.apache.activemq.util.MessageIdList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import javax.jms.MessageConsumer; +import java.util.Iterator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +@RunWith(BlockJUnit4ClassRunner.class) +public class SimpleDispatchPolicyTest extends QueueSubscriptionTest { + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + + PolicyEntry policy = new PolicyEntry(); + policy.setDispatchPolicy(new SimpleDispatchPolicy()); + policy.setSubscriptionRecoveryPolicy(new FixedCountSubscriptionRecoveryPolicy()); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + return broker; + } + + @Override + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersSmallMessagesLargePrefetch() throws Exception { + super.testOneProducerTwoConsumersSmallMessagesLargePrefetch(); + + // One consumer should have received all messages, and the rest none + // assertOneConsumerReceivedAllMessages(messageCount); + } + + @Override + @Test(timeout = 60 * 1000) + public void testOneProducerTwoConsumersLargeMessagesLargePrefetch() throws Exception { + super.testOneProducerTwoConsumersLargeMessagesLargePrefetch(); + + // One consumer should have received all messages, and the rest none + // assertOneConsumerReceivedAllMessages(messageCount); + } + + public void assertOneConsumerReceivedAllMessages(int messageCount) throws Exception { + boolean found = false; + for (Iterator i = consumers.keySet().iterator(); i.hasNext();) { + MessageIdList messageIdList = consumers.get(i.next()); + int count = messageIdList.getMessageCount(); + if (count > 0) { + if (found) { + fail("No other consumers should have received any messages"); + } else { + assertEquals("Consumer should have received all messages.", messageCount, count); + found = true; + } + } + } + + if (!found) { + fail("At least one consumer should have received all messages"); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/StrictOrderDispatchPolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/StrictOrderDispatchPolicyTest.java new file mode 100644 index 0000000000..dbeabfe941 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/StrictOrderDispatchPolicyTest.java @@ -0,0 +1,133 @@ +/** + * 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.broker.policy; + +import java.util.Iterator; + +import javax.jms.MessageConsumer; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TopicSubscriptionTest; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.StrictOrderDispatchPolicy; +import org.apache.activemq.util.MessageIdList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import static org.junit.Assert.*; + +@RunWith(BlockJUnit4ClassRunner.class) +public class StrictOrderDispatchPolicyTest extends TopicSubscriptionTest { + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + + PolicyEntry policy = new PolicyEntry(); + policy.setDispatchPolicy(new StrictOrderDispatchPolicy()); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + return broker; + } + + @Test + @Override + public void testOneProducerTwoConsumersLargeMessagesOnePrefetch() throws Exception { + super.testOneProducerTwoConsumersLargeMessagesOnePrefetch(); + + assertReceivedMessagesAreOrdered(); + } + + @Test + @Override + public void testOneProducerTwoConsumersSmallMessagesOnePrefetch() throws Exception { + super.testOneProducerTwoConsumersSmallMessagesOnePrefetch(); + + assertReceivedMessagesAreOrdered(); + } + + @Test + @Override + public void testOneProducerTwoConsumersSmallMessagesLargePrefetch() throws Exception { + super.testOneProducerTwoConsumersSmallMessagesLargePrefetch(); + + assertReceivedMessagesAreOrdered(); + } + + @Test + @Override + public void testOneProducerTwoConsumersLargeMessagesLargePrefetch() throws Exception { + super.testOneProducerTwoConsumersLargeMessagesLargePrefetch(); + + assertReceivedMessagesAreOrdered(); + } + + @Test + @Override + public void testOneProducerManyConsumersFewMessages() throws Exception { + super.testOneProducerManyConsumersFewMessages(); + + assertReceivedMessagesAreOrdered(); + } + + + @Test + @Override + public void testOneProducerManyConsumersManyMessages() throws Exception { + super.testOneProducerManyConsumersManyMessages(); + + assertReceivedMessagesAreOrdered(); + } + + @Test + @Override + public void testManyProducersOneConsumer() throws Exception { + super.testManyProducersOneConsumer(); + + assertReceivedMessagesAreOrdered(); + } + + @Test + @Override + public void testManyProducersManyConsumers() throws Exception { + super.testManyProducersManyConsumers(); + + assertReceivedMessagesAreOrdered(); + } + + public void assertReceivedMessagesAreOrdered() throws Exception { + // If there is only one consumer, messages is definitely ordered + if (consumers.size() <= 1) { + return; + } + + // Get basis of order + Iterator i = consumers.keySet().iterator(); + MessageIdList messageOrder = (MessageIdList)consumers.get(i.next()); + + for (; i.hasNext();) { + MessageIdList messageIdList = (MessageIdList)consumers.get(i.next()); + assertTrue("Messages are not ordered.", messageOrder.equals(messageIdList)); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/cursor.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/cursor.xml new file mode 100644 index 0000000000..d067a2c72d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/cursor.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/individual-dlq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/individual-dlq.xml new file mode 100644 index 0000000000..e79ea926da --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/policy/individual-dlq.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationGCTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationGCTest.java new file mode 100644 index 0000000000..17bf2b242f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationGCTest.java @@ -0,0 +1,113 @@ +/** + * 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.broker.region; + +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +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; + +public class DestinationGCTest extends EmbeddedBrokerTestSupport { + + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + ActiveMQQueue otherQueue = new ActiveMQQueue("TEST-OTHER"); + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.setDestinations(new ActiveMQDestination[] {queue}); + broker.setSchedulePeriodForDestinationPurge(1000); + broker.setMaxPurgedDestinationsPerSweep(1); + PolicyEntry entry = new PolicyEntry(); + entry.setGcInactiveDestinations(true); + entry.setInactiveTimoutBeforeGC(3000); + PolicyMap map = new PolicyMap(); + map.setDefaultEntry(entry); + broker.setDestinationPolicy(map); + return broker; + } + + public void testDestinationGCWithActiveConsumers() throws Exception { + assertEquals(1, broker.getAdminView().getQueues().length); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?create=false"); + Connection connection = factory.createConnection(); + 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) { + } + }); + connection.start(); + + TimeUnit.SECONDS.sleep(5); + + assertTrue("After GC runs there should be one Queue.", Wait.waitFor(new Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker.getAdminView().getQueues().length == 1; + } + })); + + connection.close(); + } + + public void testDestinationGc() throws Exception { + assertEquals(1, broker.getAdminView().getQueues().length); + assertTrue("After GC runs the Queue should be empty.", Wait.waitFor(new Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker.getAdminView().getQueues().length == 0; + } + })); + } + + public void testDestinationGcLimit() throws Exception { + + broker.getAdminView().addQueue("TEST1"); + broker.getAdminView().addQueue("TEST2"); + broker.getAdminView().addQueue("TEST3"); + broker.getAdminView().addQueue("TEST4"); + + assertEquals(5, broker.getAdminView().getQueues().length); + Thread.sleep(7000); + int queues = broker.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 broker.getAdminView().getQueues().length == 0; + } + })); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationRemoveRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationRemoveRestartTest.java new file mode 100644 index 0000000000..06011fe6f7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationRemoveRestartTest.java @@ -0,0 +1,117 @@ +/** + * 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.broker.region; + +import junit.framework.Test; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; + +// from https://issues.apache.org/activemq/browse/AMQ-2216 +public class DestinationRemoveRestartTest extends CombinationTestSupport { + private final static String destinationName = "TEST"; + public byte destinationType = ActiveMQDestination.QUEUE_TYPE; + BrokerService broker; + + @Override + protected void setUp() throws Exception { + broker = createBroker(); + } + + private BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setUseJmx(false); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(true); + broker.start(); + return broker; + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + } + + public void initCombosForTestCheckDestinationRemoveActionAfterRestart() { + addCombinationValues("destinationType", new Object[]{Byte.valueOf(ActiveMQDestination.QUEUE_TYPE), + Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testCheckDestinationRemoveActionAfterRestart() throws Exception { + doAddDestination(); + doRemoveDestination(); + broker.stop(); + broker.waitUntilStopped(); + broker = createBroker(); + doCheckRemoveActionAfterRestart(); + } + + public void doAddDestination() throws Exception { + boolean res = false; + + ActiveMQDestination amqDestination = + ActiveMQDestination.createDestination(destinationName, destinationType); + broker.getRegionBroker().addDestination(broker.getAdminConnectionContext(), amqDestination,true); + + final ActiveMQDestination[] list = broker.getRegionBroker().getDestinations(); + for (final ActiveMQDestination element : list) { + final Destination destination = broker.getDestination(element); + if (destination.getActiveMQDestination().getPhysicalName().equals(destinationName)) { + res = true; + break; + } + } + + assertTrue("Adding destination Failed", res); + } + + public void doRemoveDestination() throws Exception { + boolean res = true; + + broker.removeDestination(ActiveMQDestination.createDestination(destinationName, destinationType)); + final ActiveMQDestination[] list = broker.getRegionBroker().getDestinations(); + for (final ActiveMQDestination element : list) { + final Destination destination = broker.getDestination(element); + if (destination.getActiveMQDestination().getPhysicalName().equals(destinationName)) { + res = false; + break; + } + } + + assertTrue("Removing destination Failed", res); + } + + + public void doCheckRemoveActionAfterRestart() throws Exception { + boolean res = true; + + final ActiveMQDestination[] list = broker.getRegionBroker().getDestinations(); + for (final ActiveMQDestination element : list) { + final Destination destination = broker.getDestination(element); + if (destination.getActiveMQDestination().getPhysicalName().equals(destinationName)) { + res = false; + break; + } + } + + assertTrue("The removed destination is reloaded after restart !", res); + } + + public static Test suite() { + return suite(DestinationRemoveRestartTest.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueDuplicatesFromStoreTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueDuplicatesFromStoreTest.java new file mode 100644 index 0000000000..f69c380fa5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueDuplicatesFromStoreTest.java @@ -0,0 +1,407 @@ +/** + * 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.broker.region; + +import java.io.IOException; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.InvalidSelectorException; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatchNotification; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.MessagePull; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.Response; +import org.apache.activemq.filter.MessageEvaluationContext; +import org.apache.activemq.management.CountStatisticImpl; +import org.apache.activemq.state.ProducerState; +import org.apache.activemq.store.MessageStore; +import org.apache.activemq.store.PersistenceAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author gtully + * @see https://issues.apache.org/activemq/browse/AMQ-2020 + **/ +public class QueueDuplicatesFromStoreTest extends TestCase { + private static final Logger LOG = LoggerFactory + .getLogger(QueueDuplicatesFromStoreTest.class); + + ActiveMQQueue destination = new ActiveMQQueue("queue-" + + QueueDuplicatesFromStoreTest.class.getSimpleName()); + BrokerService brokerService; + + final static String mesageIdRoot = "11111:22222:"; + final int messageBytesSize = 256; + final String text = new String(new byte[messageBytesSize]); + + final int ackStartIndex = 100; + final int ackWindow = 50; + final int ackBatchSize = 50; + final int fullWindow = 200; + protected int count = 5000; + + @Override + public void setUp() throws Exception { + brokerService = createBroker(); + brokerService.setUseJmx(false); + brokerService.deleteAllMessages(); + brokerService.start(); + } + + protected BrokerService createBroker() throws Exception { + return new BrokerService(); + } + + @Override + public void tearDown() throws Exception { + brokerService.stop(); + } + + public void testNoDuplicateAfterCacheFullAndAckedWithLargeAuditDepth() throws Exception { + doTestNoDuplicateAfterCacheFullAndAcked(1024*10); + } + + public void testNoDuplicateAfterCacheFullAndAckedWithSmallAuditDepth() throws Exception { + doTestNoDuplicateAfterCacheFullAndAcked(512); + } + + public void doTestNoDuplicateAfterCacheFullAndAcked(final int auditDepth) throws Exception { + final PersistenceAdapter persistenceAdapter = brokerService.getPersistenceAdapter(); + final MessageStore queueMessageStore = + persistenceAdapter.createQueueMessageStore(destination); + final ConnectionContext contextNotInTx = new ConnectionContext(); + final ConsumerInfo consumerInfo = new ConsumerInfo(); + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + consumerInfo.setExclusive(true); + final Queue queue = new Queue(brokerService, destination, + queueMessageStore, destinationStatistics, brokerService.getTaskRunnerFactory()); + + // a workaround for this issue + // queue.setUseCache(false); + queue.systemUsage.getMemoryUsage().setLimit(1024 * 1024 * 10); + queue.setMaxAuditDepth(auditDepth); + queue.initialize(); + queue.start(); + + + ProducerBrokerExchange producerExchange = new ProducerBrokerExchange(); + ProducerInfo producerInfo = new ProducerInfo(); + ProducerState producerState = new ProducerState(producerInfo); + producerExchange.setProducerState(producerState); + producerExchange.setConnectionContext(contextNotInTx); + + final CountDownLatch receivedLatch = new CountDownLatch(count); + final AtomicLong ackedCount = new AtomicLong(0); + final AtomicLong enqueueCounter = new AtomicLong(0); + final Vector errors = new Vector(); + + // populate the queue store, exceed memory limit so that cache is disabled + for (int i = 0; i < count; i++) { + Message message = getMessage(i); + queue.send(producerExchange, message); + } + + assertEquals("store count is correct", count, queueMessageStore.getMessageCount()); + + // pull from store in small windows + Subscription subscription = new Subscription() { + + @Override + public void add(MessageReference node) throws Exception { + if (enqueueCounter.get() != node.getMessageId().getProducerSequenceId()) { + errors.add("Not in sequence at: " + enqueueCounter.get() + ", received: " + + node.getMessageId().getProducerSequenceId()); + } + assertEquals("is in order", enqueueCounter.get(), node + .getMessageId().getProducerSequenceId()); + receivedLatch.countDown(); + enqueueCounter.incrementAndGet(); + node.decrementReferenceCount(); + } + + @Override + public void add(ConnectionContext context, Destination destination) + throws Exception { + } + + @Override + public int countBeforeFull() { + if (isFull()) { + return 0; + } else { + return fullWindow - (int) (enqueueCounter.get() - ackedCount.get()); + } + } + + @Override + public void destroy() { + }; + + @Override + public void gc() { + } + + @Override + public ConsumerInfo getConsumerInfo() { + return consumerInfo; + } + + @Override + public ConnectionContext getContext() { + return null; + } + + @Override + public long getDequeueCounter() { + return 0; + } + + @Override + public long getDispatchedCounter() { + return 0; + } + + @Override + public int getDispatchedQueueSize() { + return 0; + } + + @Override + public long getEnqueueCounter() { + return 0; + } + + @Override + public int getInFlightSize() { + return 0; + } + + @Override + public int getInFlightUsage() { + return 0; + } + + @Override + public ObjectName getObjectName() { + return null; + } + + @Override + public int getPendingQueueSize() { + return 0; + } + + @Override + public int getPrefetchSize() { + return 0; + } + + @Override + public String getSelector() { + return null; + } + + @Override + public boolean isBrowser() { + return false; + } + + @Override + public boolean isFull() { + return (enqueueCounter.get() - ackedCount.get()) >= fullWindow; + } + + @Override + public boolean isHighWaterMark() { + return false; + } + + @Override + public boolean isLowWaterMark() { + return false; + } + + @Override + public boolean isRecoveryRequired() { + return false; + } + + @Override + public boolean matches(MessageReference node, + MessageEvaluationContext context) throws IOException { + return true; + } + + @Override + public boolean matches(ActiveMQDestination destination) { + return true; + } + + @Override + public void processMessageDispatchNotification( + MessageDispatchNotification mdn) throws Exception { + } + + @Override + public Response pullMessage(ConnectionContext context, + MessagePull pull) throws Exception { + return null; + } + + @Override + public boolean isWildcard() { + return false; + } + + @Override + public List remove(ConnectionContext context, + Destination destination) throws Exception { + return null; + } + + @Override + public void setObjectName(ObjectName objectName) { + } + + @Override + public void setSelector(String selector) + throws InvalidSelectorException, + UnsupportedOperationException { + } + + @Override + public void updateConsumerPrefetch(int newPrefetch) { + } + + @Override + public boolean addRecoveredMessage(ConnectionContext context, + MessageReference message) throws Exception { + return false; + } + + @Override + public ActiveMQDestination getActiveMQDestination() { + return destination; + } + + @Override + public void acknowledge(ConnectionContext context, MessageAck ack) + throws Exception { + } + + @Override + public int getCursorMemoryHighWaterMark(){ + return 0; + } + + @Override + public void setCursorMemoryHighWaterMark( + int cursorMemoryHighWaterMark) { + } + + @Override + public boolean isSlowConsumer() { + return false; + } + + @Override + public void unmatched(MessageReference node) throws IOException { + } + + @Override + public long getTimeOfLastMessageAck() { + return 0; + } + + @Override + public long getConsumedCount() { + return 0; + } + + public void incrementConsumedCount(){ + + } + + public void resetConsumedCount(){ + + } + }; + + queue.addSubscription(contextNotInTx, subscription); + int removeIndex = 0; + do { + // Simulate periodic acks in small but recent windows + long receivedCount = enqueueCounter.get(); + if (receivedCount > ackStartIndex) { + if (receivedCount >= removeIndex + ackWindow) { + for (int j = 0; j < ackBatchSize; j++, removeIndex++) { + ackedCount.incrementAndGet(); + MessageAck ack = new MessageAck(); + ack.setLastMessageId(new MessageId(mesageIdRoot + + removeIndex)); + ack.setMessageCount(1); + queue.removeMessage(contextNotInTx, subscription, + new IndirectMessageReference( + getMessage(removeIndex)), ack); + queue.wakeup(); + + } + if (removeIndex % 1000 == 0) { + LOG.info("acked: " + removeIndex); + persistenceAdapter.checkpoint(true); + } + } + } + + } while (!receivedLatch.await(0, TimeUnit.MILLISECONDS) && errors.isEmpty()); + + assertTrue("There are no errors: " + errors, errors.isEmpty()); + assertEquals(count, enqueueCounter.get()); + assertEquals("store count is correct", count - removeIndex, + queueMessageStore.getMessageCount()); + } + + private Message getMessage(int i) throws Exception { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setMessageId(new MessageId(mesageIdRoot + i)); + message.setDestination(destination); + message.setPersistent(true); + message.setResponseRequired(true); + message.setText("Msg:" + i + " " + text); + assertEquals(message.getMessageId().getProducerSequenceId(), i); + return message; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueOptimizedDispatchExceptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueOptimizedDispatchExceptionTest.java new file mode 100644 index 0000000000..b46169e194 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueOptimizedDispatchExceptionTest.java @@ -0,0 +1,255 @@ +/** + * 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.broker.region; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.Connection; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.Connector; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.Command; +import org.apache.activemq.command.ConnectionControl; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.Response; +import org.apache.activemq.state.ProducerState; +import org.apache.activemq.store.MessageStore; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.usage.MemoryUsage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QueueOptimizedDispatchExceptionTest { + + private static final Logger LOG = LoggerFactory.getLogger(QueueOptimizedDispatchExceptionTest.class); + + private static final String brokerName = "testBroker"; + private static final String brokerUrl = "vm://" + brokerName; + private static final int count = 50; + + private final static String mesageIdRoot = "11111:22222:"; + private final ActiveMQQueue destination = new ActiveMQQueue("queue-" + + QueueOptimizedDispatchExceptionTest.class.getSimpleName()); + private final int messageBytesSize = 256; + private final String text = new String(new byte[messageBytesSize]); + + private BrokerService broker; + + @Before + public void setUp() throws Exception { + + // Setup and start the broker + broker = new BrokerService(); + broker.setBrokerName(brokerName); + broker.setPersistent(false); + broker.setSchedulerSupport(false); + broker.setUseJmx(false); + broker.setUseShutdownHook(false); + broker.addConnector(brokerUrl); + + // Start the broker + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + private class MockMemoryUsage extends MemoryUsage { + + private boolean full = true; + + public void setFull(boolean full) { + this.full = full; + } + + @Override + public boolean isFull() { + return full; + } + } + + @Test + public void TestOptimizedDispatchCME() throws Exception { + final PersistenceAdapter persistenceAdapter = broker.getPersistenceAdapter(); + final MessageStore queueMessageStore = + persistenceAdapter.createQueueMessageStore(destination); + final ConnectionContext contextNotInTx = new ConnectionContext(); + contextNotInTx.setConnection(new Connection() { + + @Override + public void stop() throws Exception { + } + + @Override + public void start() throws Exception { + } + + @Override + public void updateClient(ConnectionControl control) { + } + + @Override + public void serviceExceptionAsync(IOException e) { + } + + @Override + public void serviceException(Throwable error) { + } + + @Override + public Response service(Command command) { + return null; + } + + @Override + public boolean isSlow() { + return false; + } + + @Override + public boolean isNetworkConnection() { + return false; + } + + @Override + public boolean isManageable() { + return false; + } + + @Override + public boolean isFaultTolerantConnection() { + return false; + } + + @Override + public boolean isConnected() { + return true; + } + + @Override + public boolean isBlocked() { + return false; + } + + @Override + public boolean isActive() { + return false; + } + + @Override + public ConnectionStatistics getStatistics() { + return null; + } + + @Override + public String getRemoteAddress() { + return null; + } + + @Override + public int getDispatchQueueSize() { + return 0; + } + + @Override + public Connector getConnector() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getConnectionId() { + return null; + } + + @Override + public void dispatchSync(Command message) { + } + + @Override + public void dispatchAsync(Command command) { + } + + @Override + public int getActiveTransactionCount() { + return 0; + } + + @Override + public Long getOldestActiveTransactionDuration() { + return null; + } + }); + + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + final Queue queue = new Queue(broker, destination, + queueMessageStore, destinationStatistics, broker.getTaskRunnerFactory()); + + final MockMemoryUsage usage = new MockMemoryUsage(); + + queue.setOptimizedDispatch(true); + queue.initialize(); + queue.start(); + queue.memoryUsage = usage; + + ProducerBrokerExchange producerExchange = new ProducerBrokerExchange(); + ProducerInfo producerInfo = new ProducerInfo(); + ProducerState producerState = new ProducerState(producerInfo); + producerExchange.setProducerState(producerState); + producerExchange.setConnectionContext(contextNotInTx); + + // populate the queue store, exceed memory limit so that cache is disabled + for (int i = 0; i < count; i++) { + Message message = getMessage(i); + queue.send(producerExchange, message); + } + + usage.setFull(false); + + try { + queue.wakeup(); + } catch(Exception e) { + LOG.error("Queue threw an unexpected exception: " + e.toString()); + fail("Should not throw an exception."); + } + } + + private Message getMessage(int i) throws Exception { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setMessageId(new MessageId(mesageIdRoot + i)); + message.setDestination(destination); + message.setPersistent(false); + message.setResponseRequired(true); + message.setText("Msg:" + i + " " + text); + assertEquals(message.getMessageId().getProducerSequenceId(), i); + return message; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueuePurgeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueuePurgeTest.java new file mode 100644 index 0000000000..91209379ad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueuePurgeTest.java @@ -0,0 +1,216 @@ +/** + * 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.broker.region; + +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.Level; +import org.apache.log4j.spi.LoggingEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QueuePurgeTest extends CombinationTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(QueuePurgeTest.class); + private static final int NUM_TO_SEND = 20000; + private final String MESSAGE_TEXT = new String(new byte[1024]); + BrokerService broker; + ConnectionFactory factory; + Connection connection; + Session session; + Queue queue; + MessageConsumer consumer; + + protected void setUp() throws Exception { + setMaxTestTime(10*60*1000); // 10 mins + setAutoFail(true); + super.setUp(); + broker = new BrokerService(); + + File testDataDir = new File("target/activemq-data/QueuePurgeTest"); + broker.setDataDirectoryFile(testDataDir); + broker.setUseJmx(true); + broker.setDeleteAllMessagesOnStartup(true); + broker.getSystemUsage().getMemoryUsage().setLimit(1024l*1024*64); + KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); + persistenceAdapter.setDirectory(new File(testDataDir, "kahadb")); + broker.setPersistenceAdapter(persistenceAdapter); + broker.addConnector("tcp://localhost:0"); + broker.start(); + factory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri().toString()); + connection = factory.createConnection(); + connection.start(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (consumer != null) { + consumer.close(); + } + session.close(); + connection.stop(); + connection.close(); + broker.stop(); + } + + public void testPurgeLargeQueue() throws Exception { + applyBrokerSpoolingPolicy(); + createProducerAndSendMessages(NUM_TO_SEND); + QueueViewMBean proxy = getProxyToQueueViewMBean(); + LOG.info("purging.."); + + org.apache.log4j.Logger log4jLogger = org.apache.log4j.Logger.getLogger(org.apache.activemq.broker.region.Queue.class); + final AtomicBoolean gotPurgeLogMessage = new AtomicBoolean(false); + + Appender appender = new DefaultTestAppender() { + @Override + public void doAppend(LoggingEvent event) { + if (event.getMessage() instanceof String) { + String message = (String) event.getMessage(); + if (message.contains("purged of " + NUM_TO_SEND +" messages")) { + LOG.info("Received a log message: {} ", event.getMessage()); + gotPurgeLogMessage.set(true); + } + } + } + }; + + Level level = log4jLogger.getLevel(); + log4jLogger.setLevel(Level.INFO); + log4jLogger.addAppender(appender); + try { + + proxy.purge(); + + } finally { + log4jLogger.setLevel(level); + log4jLogger.removeAppender(appender); + } + + assertEquals("Queue size is not zero, it's " + proxy.getQueueSize(), 0, + proxy.getQueueSize()); + assertTrue("cache is disabled, temp store being used", !proxy.isCacheEnabled()); + assertTrue("got expected info purge log message", gotPurgeLogMessage.get()); + } + + public void testRepeatedExpiryProcessingOfLargeQueue() throws Exception { + applyBrokerSpoolingPolicy(); + final int expiryPeriod = 500; + applyExpiryDuration(expiryPeriod); + createProducerAndSendMessages(NUM_TO_SEND); + 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); + assertEquals("Queue size is has not changed " + proxy.getQueueSize(), NUM_TO_SEND, + proxy.getQueueSize()); + } + + + private void applyExpiryDuration(int i) { + broker.getDestinationPolicy().getDefaultEntry().setExpireMessagesPeriod(i); + } + + private void applyBrokerSpoolingPolicy() { + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setProducerFlowControl(false); + PendingQueueMessageStoragePolicy pendingQueuePolicy = new FilePendingQueueMessageStoragePolicy(); + defaultEntry.setPendingQueuePolicy(pendingQueuePolicy); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + } + + + public void testPurgeLargeQueueWithConsumer() throws Exception { + applyBrokerSpoolingPolicy(); + createProducerAndSendMessages(NUM_TO_SEND); + QueueViewMBean proxy = getProxyToQueueViewMBean(); + createConsumer(); + long start = System.currentTimeMillis(); + LOG.info("purging.."); + proxy.purge(); + LOG.info("purge done: " + (System.currentTimeMillis() - start) + "ms"); + assertEquals("Queue size is not zero, it's " + proxy.getQueueSize(), 0, + proxy.getQueueSize()); + assertEquals("usage goes to duck", 0, proxy.getMemoryPercentUsage()); + Message msg; + do { + msg = consumer.receive(1000); + if (msg != null) { + msg.acknowledge(); + } + } while (msg != null); + assertEquals("Queue size not valid", 0, proxy.getQueueSize()); + } + + private QueueViewMBean getProxyToQueueViewMBean() + throws MalformedObjectNameException, JMSException { + ObjectName queueViewMBeanName = + new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + + queue.getQueueName()); + QueueViewMBean proxy = (QueueViewMBean) broker.getManagementContext() + .newProxyInstance(queueViewMBeanName, + QueueViewMBean.class, true); + return proxy; + } + + private void createProducerAndSendMessages(int numToSend) throws Exception { + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + queue = session.createQueue("test1"); + MessageProducer producer = session.createProducer(queue); + for (int i = 0; i < numToSend; i++) { + TextMessage message = session.createTextMessage(MESSAGE_TEXT + i); + if (i != 0 && i % 10000 == 0) { + LOG.info("sent: " + i); + } + producer.send(message); + } + producer.close(); + } + + private void createConsumer() throws Exception { + consumer = session.createConsumer(queue); + // wait for buffer fill out + Thread.sleep(5 * 1000); + for (int i = 0; i < 500; ++i) { + Message message = consumer.receive(); + message.acknowledge(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueResendDuringShutdownTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueResendDuringShutdownTest.java new file mode 100644 index 0000000000..0439fa847c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/QueueResendDuringShutdownTest.java @@ -0,0 +1,250 @@ +/** + * 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.broker.region; + +import java.io.File; + +import static org.junit.matchers.JUnitMatchers.containsString; +import static org.junit.Assert.*; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.broker.BrokerService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.junit.*; + +/** + * Confirm that the broker does not resend unacknowledged messages during a broker shutdown. + */ +public class QueueResendDuringShutdownTest { + private static final Logger LOG = LoggerFactory.getLogger(QueueResendDuringShutdownTest.class); + public static final int NUM_CONNECTION_TO_TEST = 8; + + private static boolean iterationFoundFailure = false; + + private BrokerService broker; + private ActiveMQConnectionFactory factory; + private Connection[] connections; + private Connection producerConnection; + private Queue queue; + + private Object messageReceiveSync = new Object(); + private int receiveCount; + + @Before + public void setUp () throws Exception { + this.receiveCount = 0; + + this.broker = new BrokerService(); + this.broker.setPersistent(false); + this.broker.start(); + this.broker.waitUntilStarted(); + + this.factory = new ActiveMQConnectionFactory(broker.getVmConnectorURI()); + this.queue = new ActiveMQQueue("TESTQUEUE"); + + connections = new Connection[NUM_CONNECTION_TO_TEST]; + int iter = 0; + while ( iter < NUM_CONNECTION_TO_TEST ) { + this.connections[iter] = factory.createConnection(); + iter++; + } + + this.producerConnection = factory.createConnection(); + this.producerConnection.start(); + } + + @After + public void cleanup () throws Exception { + for ( Connection oneConnection : connections ) { + if ( oneConnection != null ) { + closeConnection(oneConnection); + } + } + connections = null; + + if ( this.producerConnection != null ) { + closeConnection(this.producerConnection); + this.producerConnection = null; + } + + this.broker.stop(); + this.broker.waitUntilStopped(); + } + + @Test(timeout=3000) + public void testRedeliverAtBrokerShutdownAutoAckMsgListenerIter1 () throws Throwable { + runTestIteration(); + } + + @Test(timeout=3000) + public void testRedeliverAtBrokerShutdownAutoAckMsgListenerIter2 () throws Throwable { + runTestIteration(); + } + + @Test(timeout=3000) + public void testRedeliverAtBrokerShutdownAutoAckMsgListenerIter3 () throws Throwable { + runTestIteration(); + } + + /** + * Run one iteration of the test, skipping it if a failure was found on a prior iteration since a single failure is + * enough. Also keep track of the state of failure for the iteration. + */ + protected void runTestIteration () throws Throwable { + if ( iterationFoundFailure ) { + LOG.info("skipping test iteration; failure previously detected"); + return; + } try { + testRedeliverAtBrokerShutdownAutoAckMsgListener(); + } catch ( Throwable thrown ) { + iterationFoundFailure = true; + throw thrown; + } + } + + protected void testRedeliverAtBrokerShutdownAutoAckMsgListener () throws Exception { + // Start consumers on all of the connections + for ( Connection oneConnection : connections ) { + MessageConsumer consumer = startupConsumer(oneConnection, false, Session.AUTO_ACKNOWLEDGE); + configureMessageListener(consumer); + oneConnection.start(); + } + + // Send one message to the Queue and wait a short time for the dispatch to occur. + this.sendMessage(); + waitForMessage(1000); + + // Verify one consumer received it + assertEquals(1, this.receiveCount); + + // Shutdown the broker + this.broker.stop(); + this.broker.waitUntilStopped(); + delay(100, "give queue time flush"); + + // Verify still only one consumer received it + assertEquals(1, this.receiveCount); + } + + /** + * Start a consumer on the given connection using the session transaction and acknowledge settings given. + */ + protected MessageConsumer startupConsumer (Connection conn, boolean transInd, int ackMode) + throws JMSException { + Session sess; + MessageConsumer consumer; + + sess = conn.createSession(transInd, ackMode); + consumer = sess.createConsumer(queue); + + return consumer; + } + + /** + * Mark the receipt of a message from one of the consumers. + */ + protected void messageReceived () { + synchronized ( this ) { + this.receiveCount++; + synchronized ( this.messageReceiveSync ) { + this.messageReceiveSync.notifyAll(); + } + } + } + + /** + * Setup the MessageListener for the given consumer. The listener uses a long delay on receiving the message to + * simulate the reported case of problems at shutdown caused by a message listener's connection closing while it is + * still processing. + */ + protected void configureMessageListener (MessageConsumer consumer) throws JMSException { + final MessageConsumer fConsumer = consumer; + + consumer.setMessageListener(new MessageListener() { + public void onMessage (Message msg) { + LOG.debug("got a message on consumer {}", fConsumer); + messageReceived(); + + // Delay long enough for the consumer to get closed while this delay is active. + delay(3000, "pause so connection shutdown leads to unacked message redelivery"); + } + }); + } + + /** + * Send a test message now. + */ + protected void sendMessage () throws JMSException { + Session sess = this.producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer prod = sess.createProducer(queue); + prod.send(sess.createTextMessage("X-TEST-MSG-X")); + prod.close(); + sess.close(); + } + + /** + * Close the given connection safely and log any exception caught. + */ + protected void closeConnection (Connection conn) { + try { + conn.close(); + } catch ( JMSException jmsExc ) { + LOG.info("failed to cleanup connection", jmsExc); + } + } + + /** + * Pause for the given length of time, in milliseconds, logging an interruption if one occurs. Don't try to + * recover from interrupt - the test case does not support interrupting and such an occurrence likely means the + * test is being aborted. + */ + protected void delay (long delayMs, String desc) { + try { + Thread.sleep(delayMs); + } catch ( InterruptedException intExc ) { + LOG.warn("sleep interrupted: " + desc, intExc); + } + } + + /** + * Wait up to the specified duration for a message to be received by any consumer. + */ + protected void waitForMessage (long delayMs) { + try { + synchronized ( this.messageReceiveSync ) { + if ( this.receiveCount == 0 ) { + this.messageReceiveSync.wait(delayMs); + } + } + } catch ( InterruptedException intExc ) { + LOG.warn("sleep interrupted: wait for message to arrive"); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/SubscriptionAddRemoveQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/SubscriptionAddRemoveQueueTest.java new file mode 100644 index 0000000000..6964842614 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/SubscriptionAddRemoveQueueTest.java @@ -0,0 +1,374 @@ +/** + * 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. + */ +/** + * 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.broker.region; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.InvalidSelectorException; +import javax.management.ObjectName; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatchNotification; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.MessagePull; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.Response; +import org.apache.activemq.filter.MessageEvaluationContext; +import org.apache.activemq.state.ProducerState; +import org.apache.activemq.store.MessageStore; +import org.apache.activemq.thread.TaskRunnerFactory; +import junit.framework.TestCase; + +public class SubscriptionAddRemoveQueueTest extends TestCase { + + Queue queue; + + ConsumerInfo info = new ConsumerInfo(); + List subs = new ArrayList(); + ConnectionContext context = new ConnectionContext(); + ProducerBrokerExchange producerBrokerExchange = new ProducerBrokerExchange(); + ProducerInfo producerInfo = new ProducerInfo(); + ProducerState producerState = new ProducerState(producerInfo); + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + int numSubscriptions = 1000; + boolean working = true; + int senders = 20; + + + @Override + public void setUp() throws Exception { + BrokerService brokerService = new BrokerService(); + brokerService.start(); + DestinationStatistics parentStats = new DestinationStatistics(); + parentStats.setEnabled(true); + + TaskRunnerFactory taskFactory = new TaskRunnerFactory(); + MessageStore store = null; + + info.setDestination(destination); + info.setPrefetchSize(100); + + producerBrokerExchange.setProducerState(producerState); + producerBrokerExchange.setConnectionContext(context); + + queue = new Queue(brokerService, destination, store, parentStats, taskFactory); + queue.initialize(); + } + + public void testNoDispatchToRemovedConsumers() throws Exception { + final AtomicInteger producerId = new AtomicInteger(); + Runnable sender = new Runnable() { + public void run() { + AtomicInteger id = new AtomicInteger(); + int producerIdAndIncrement = producerId.getAndIncrement(); + while (working) { + try { + Message msg = new ActiveMQMessage(); + msg.setDestination(destination); + msg.setMessageId(new MessageId(producerIdAndIncrement + ":0:" + id.getAndIncrement())); + queue.send(producerBrokerExchange, msg); + } catch (Exception e) { + e.printStackTrace(); + fail("unexpected exception in sendMessage, ex:" + e); + } + } + } + }; + + Runnable subRemover = new Runnable() { + public void run() { + for (Subscription sub : subs) { + try { + queue.removeSubscription(context, sub, 0); + } catch (Exception e) { + e.printStackTrace(); + fail("unexpected exception in removeSubscription, ex:" + e); + } + } + } + }; + + for (int i=0;i result = executor.submit(subRemover); + result.get(); + working = false; + assertEquals("there are no subscriptions", 0, queue.getDestinationStatistics().getConsumers().getCount()); + + for (SimpleImmediateDispatchSubscription sub : subs) { + assertTrue("There are no locked messages in any removed subscriptions", !hasSomeLocks(sub.dispatched)); + } + + } + + private boolean hasSomeLocks(List dispatched) { + boolean hasLock = false; + for (MessageReference mr: dispatched) { + QueueMessageReference qmr = (QueueMessageReference) mr; + if (qmr.getLockOwner() != null) { + hasLock = true; + break; + } + } + return hasLock; + } + + public class SimpleImmediateDispatchSubscription implements Subscription, LockOwner { + + List dispatched = + Collections.synchronizedList(new ArrayList()); + + public void acknowledge(ConnectionContext context, MessageAck ack) + throws Exception { + } + + public void add(MessageReference node) throws Exception { + // immediate dispatch + QueueMessageReference qmr = (QueueMessageReference)node; + qmr.lock(this); + dispatched.add(qmr); + } + + public ConnectionContext getContext() { + return null; + } + + @Override + public int getCursorMemoryHighWaterMark() { + return 0; + } + + @Override + public void setCursorMemoryHighWaterMark(int cursorMemoryHighWaterMark) { + } + + @Override + public boolean isSlowConsumer() { + return false; + } + + @Override + public void unmatched(MessageReference node) throws IOException { + } + + @Override + public long getTimeOfLastMessageAck() { + return 0; + } + + @Override + public long getConsumedCount() { + return 0; + } + + @Override + public void incrementConsumedCount() { + } + + @Override + public void resetConsumedCount() { + } + + public void add(ConnectionContext context, Destination destination) + throws Exception { + } + + public void destroy() { + } + + public void gc() { + } + + public ConsumerInfo getConsumerInfo() { + return info; + } + + public long getDequeueCounter() { + return 0; + } + + public long getDispatchedCounter() { + return 0; + } + + public int getDispatchedQueueSize() { + return 0; + } + + public long getEnqueueCounter() { + return 0; + } + + public int getInFlightSize() { + return 0; + } + + public int getInFlightUsage() { + return 0; + } + + public ObjectName getObjectName() { + return null; + } + + public int getPendingQueueSize() { + return 0; + } + + public int getPrefetchSize() { + return 0; + } + + public String getSelector() { + return null; + } + + public boolean isBrowser() { + return false; + } + + public boolean isFull() { + return false; + } + + public boolean isHighWaterMark() { + return false; + } + + public boolean isLowWaterMark() { + return false; + } + + public boolean isRecoveryRequired() { + return false; + } + + public boolean isSlave() { + return false; + } + + public boolean matches(MessageReference node, + MessageEvaluationContext context) throws IOException { + return true; + } + + public boolean matches(ActiveMQDestination destination) { + return false; + } + + public void processMessageDispatchNotification( + MessageDispatchNotification mdn) throws Exception { + } + + public Response pullMessage(ConnectionContext context, MessagePull pull) + throws Exception { + return null; + } + + @Override + public boolean isWildcard() { + return false; + } + + public List remove(ConnectionContext context, + Destination destination) throws Exception { + return new ArrayList(dispatched); + } + + public void setObjectName(ObjectName objectName) { + } + + public void setSelector(String selector) + throws InvalidSelectorException, UnsupportedOperationException { + } + + public void updateConsumerPrefetch(int newPrefetch) { + } + + public boolean addRecoveredMessage(ConnectionContext context, + MessageReference message) throws Exception { + return false; + } + + public ActiveMQDestination getActiveMQDestination() { + return null; + } + + public int getLockPriority() { + return 0; + } + + public boolean isLockExclusive() { + return false; + } + + public void addDestination(Destination destination) { + } + + public void removeDestination(Destination destination) { + } + + public int countBeforeFull() { + return 10; + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/UniquePropertyMessageEvictionStrategyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/UniquePropertyMessageEvictionStrategyTest.java new file mode 100644 index 0000000000..5657e5cd4b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/UniquePropertyMessageEvictionStrategyTest.java @@ -0,0 +1,105 @@ +/** + * 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.broker.region; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.ConstantPendingMessageLimitStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.UniquePropertyMessageEvictionStrategy; + +import javax.jms.*; +import java.util.ArrayList; +import java.util.List; + +public class UniquePropertyMessageEvictionStrategyTest extends EmbeddedBrokerTestSupport { + + + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setTopic(">"); + + entry.setAdvisoryForDiscardingMessages(true); + entry.setTopicPrefetch(1); + + ConstantPendingMessageLimitStrategy pendingMessageLimitStrategy = new ConstantPendingMessageLimitStrategy(); + pendingMessageLimitStrategy.setLimit(10); + entry.setPendingMessageLimitStrategy(pendingMessageLimitStrategy); + + + UniquePropertyMessageEvictionStrategy messageEvictionStrategy = new UniquePropertyMessageEvictionStrategy(); + messageEvictionStrategy.setPropertyName("sequenceI"); + entry.setMessageEvictionStrategy(messageEvictionStrategy); + + // let evicted messages disappear + entry.setDeadLetterStrategy(null); + policyEntries.add(entry); + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + broker.setDestinationPolicy(policyMap); + + return broker; + } + + public void testEviction() throws Exception { + Connection conn = connectionFactory.createConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + javax.jms.Topic destination = session.createTopic("TEST"); + + MessageProducer producer = session.createProducer(destination); + MessageConsumer consumer = session.createConsumer(destination); + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + TextMessage msg = session.createTextMessage("message " + i + j); + msg.setIntProperty("sequenceI", i); + msg.setIntProperty("sequenceJ", j); + producer.send(msg); + Thread.sleep(100); + } + } + + + for (int i = 0; i < 11; i++) { + javax.jms.Message msg = consumer.receive(1000); + assertNotNull(msg); + int seqI = msg.getIntProperty("sequenceI"); + int seqJ = msg.getIntProperty("sequenceJ"); + if (i ==0 ) { + assertEquals(0, seqI); + assertEquals(0, seqJ); + } else { + assertEquals(9, seqJ); + assertEquals(i - 1, seqI); + } + //System.out.println(msg.getIntProperty("sequenceI") + " " + msg.getIntProperty("sequenceJ")); + } + + javax.jms.Message msg = consumer.receive(1000); + assertNull(msg); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorDurableTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorDurableTest.java new file mode 100644 index 0000000000..12589ca238 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorDurableTest.java @@ -0,0 +1,57 @@ +/** + * 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.broker.region.cursors; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; +import org.apache.activemq.broker.BrokerService; + +/** + * + */ +public class CursorDurableTest extends CursorSupport { + + protected Destination getDestination(Session session) throws JMSException { + String topicName = getClass().getName(); + return session.createTopic(topicName); + } + + protected Connection getConsumerConnection(ConnectionFactory fac) throws JMSException { + Connection connection = fac.createConnection(); + connection.setClientID("testConsumer"); + connection.start(); + return connection; + } + + protected MessageConsumer getConsumer(Connection connection) throws Exception { + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = (Topic)getDestination(consumerSession); + MessageConsumer consumer = consumerSession.createDurableSubscriber(topic, "testConsumer"); + return consumer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(bindAddress); + answer.setDeleteAllMessagesOnStartup(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorQueueStoreTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorQueueStoreTest.java new file mode 100644 index 0000000000..b0668d9138 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorQueueStoreTest.java @@ -0,0 +1,75 @@ +/** + * 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.broker.region.cursors; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.StorePendingQueueMessageStoragePolicy; + +/** + * + */ +public class CursorQueueStoreTest extends CursorSupport { + + protected Destination getDestination(Session session) throws JMSException { + String queueName = "QUEUE" + getClass().getName(); + return session.createQueue(queueName); + } + + protected Connection getConsumerConnection(ConnectionFactory fac) throws JMSException { + Connection connection = fac.createConnection(); + connection.setClientID("testConsumer"); + connection.start(); + return connection; + } + + protected MessageConsumer getConsumer(Connection connection) throws Exception { + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = getDestination(consumerSession); + MessageConsumer consumer = consumerSession.createConsumer(dest); + return consumer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + PolicyEntry policy = new PolicyEntry(); + policy.setPendingQueuePolicy(new StorePendingQueueMessageStoragePolicy()); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + answer.setDestinationPolicy(pMap); + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(bindAddress); + answer.setDeleteAllMessagesOnStartup(true); + } + + public static Test suite() { + return suite(CursorQueueStoreTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorSupport.java new file mode 100644 index 0000000000..3c014a6728 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/CursorSupport.java @@ -0,0 +1,198 @@ +/** + * 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.broker.region.cursors; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +/** + * + */ +public abstract class CursorSupport extends CombinationTestSupport { + + public int MESSAGE_COUNT = 500; + public int PREFETCH_SIZE = 50; + private static final Logger LOG = LoggerFactory.getLogger(CursorSupport.class); + + protected BrokerService broker; + protected String bindAddress = "tcp://localhost:60706"; + + protected abstract Destination getDestination(Session session) throws JMSException; + + protected abstract MessageConsumer getConsumer(Connection connection) throws Exception; + + protected abstract void configureBroker(BrokerService answer) throws Exception; + + public void testSendFirstThenConsume() throws Exception { + ConnectionFactory factory = createConnectionFactory(); + Connection consumerConnection = getConsumerConnection(factory); + MessageConsumer consumer = getConsumer(consumerConnection); + consumerConnection.close(); + Connection producerConnection = factory.createConnection(); + producerConnection.start(); + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(getDestination(session)); + List senderList = new ArrayList(); + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message msg = session.createTextMessage("test" + i); + senderList.add(msg); + producer.send(msg); + } + producerConnection.close(); + // now consume the messages + consumerConnection = getConsumerConnection(factory); + // create durable subs + consumer = getConsumer(consumerConnection); + List consumerList = new ArrayList(); + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message msg = consumer.receive(1000*5); + assertNotNull("Message "+i+" was missing.", msg); + consumerList.add(msg); + } + assertEquals(senderList, consumerList); + consumerConnection.close(); + } + + + public void initCombosForTestSendWhilstConsume() { + addCombinationValues("MESSAGE_COUNT", new Object[] {Integer.valueOf(400), + Integer.valueOf(500)}); + addCombinationValues("PREFETCH_SIZE", new Object[] {Integer.valueOf(100), + Integer.valueOf(50)}); + } + + public void testSendWhilstConsume() throws Exception { + ConnectionFactory factory = createConnectionFactory(); + Connection consumerConnection = getConsumerConnection(factory); + // create durable subs + MessageConsumer consumer = getConsumer(consumerConnection); + consumerConnection.close(); + Connection producerConnection = factory.createConnection(); + producerConnection.start(); + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(getDestination(session)); + List senderList = new ArrayList(); + for (int i = 0; i < MESSAGE_COUNT / 10; i++) { + TextMessage msg = session.createTextMessage("test" + i); + senderList.add(msg); + producer.send(msg); + } + // now consume the messages + consumerConnection = getConsumerConnection(factory); + // create durable subs + consumer = getConsumer(consumerConnection); + final List consumerList = new ArrayList(); + final CountDownLatch latch = new CountDownLatch(1); + consumer.setMessageListener(new MessageListener() { + + public void onMessage(Message msg) { + try { + // sleep to act as a slow consumer + // which will force a mix of direct and polled dispatching + // using the cursor on the broker + Thread.sleep(50); + } catch (Exception e) { + e.printStackTrace(); + } + consumerList.add(msg); + if (consumerList.size() == MESSAGE_COUNT) { + latch.countDown(); + } + } + }); + for (int i = MESSAGE_COUNT / 10; i < MESSAGE_COUNT; i++) { + TextMessage msg = session.createTextMessage("test" + i); + senderList.add(msg); + producer.send(msg); + } + latch.await(300000, TimeUnit.MILLISECONDS); + producerConnection.close(); + consumerConnection.close(); + assertEquals("Still dipatching - count down latch not sprung", latch.getCount(), 0); + //assertEquals("cosumerList - expected: " + MESSAGE_COUNT + " but was: " + consumerList.size(), consumerList.size(), senderList.size()); + for (int i = 0; i < senderList.size(); i++) { + Message sent = senderList.get(i); + Message consumed = consumerList.get(i); + if (!sent.equals(consumed)) { + LOG.error("BAD MATCH AT POS " + i); + LOG.error(sent.toString()); + LOG.error(consumed.toString()); + /* + * log.error("\n\n\n\n\n"); for (int j = 0; j < + * consumerList.size(); j++) { log.error(consumerList.get(j)); } + */ + } + assertEquals("This should be the same at pos " + i + " in the list", sent.getJMSMessageID(), consumed.getJMSMessageID()); + } + } + + protected Connection getConsumerConnection(ConnectionFactory fac) throws JMSException { + Connection connection = fac.createConnection(); + connection.setClientID("testConsumer"); + connection.start(); + return connection; + } + + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(bindAddress); + Properties props = new Properties(); + props.setProperty("prefetchPolicy.durableTopicPrefetch", "" + PREFETCH_SIZE); + props.setProperty("prefetchPolicy.optimizeDurableTopicPrefetch", "" + PREFETCH_SIZE); + props.setProperty("prefetchPolicy.queuePrefetch", "" + PREFETCH_SIZE); + cf.setProperties(props); + return cf; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/FilePendingMessageCursorTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/FilePendingMessageCursorTestSupport.java new file mode 100644 index 0000000000..123263d95b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/FilePendingMessageCursorTestSupport.java @@ -0,0 +1,89 @@ +/** + * 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.broker.region.cursors; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.QueueMessageReference; +import org.apache.activemq.store.PList; +import org.apache.activemq.usage.SystemUsage; +import org.apache.activemq.util.ByteSequence; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class FilePendingMessageCursorTestSupport { + + protected static final Logger LOG = LoggerFactory.getLogger(FilePendingMessageCursorTestSupport.class); + protected BrokerService brokerService; + protected FilePendingMessageCursor underTest; + + @After + public void stopBroker() throws Exception { + if (brokerService != null) { + brokerService.getTempDataStore().stop(); + } + } + + private void createBrokerWithTempStoreLimit() throws Exception { + brokerService = new BrokerService(); + brokerService.setUseJmx(false); + SystemUsage usage = brokerService.getSystemUsage(); + usage.getTempUsage().setLimit(1025*1024*15); + + // put something in the temp store to on demand initialise it + PList dud = brokerService.getTempDataStore().getPList("dud"); + dud.addFirst("A", new ByteSequence("A".getBytes())); + } + + @Test + public void testAddToEmptyCursorWhenTempStoreIsFull() throws Exception { + createBrokerWithTempStoreLimit(); + SystemUsage usage = brokerService.getSystemUsage(); + assertTrue("temp store is full: %" + usage.getTempUsage().getPercentUsage(), usage.getTempUsage().isFull()); + + underTest = new FilePendingMessageCursor(brokerService.getBroker(), "test", false); + underTest.setSystemUsage(usage); + + // ok to add + underTest.addMessageLast(QueueMessageReference.NULL_MESSAGE); + + assertFalse("cursor is not full", underTest.isFull()); + } + + @Test + public void testResetClearsIterator() throws Exception { + createBrokerWithTempStoreLimit(); + + underTest = new FilePendingMessageCursor(brokerService.getBroker(), "test", false); + // ok to add + underTest.addMessageLast(QueueMessageReference.NULL_MESSAGE); + + underTest.reset(); + underTest.release(); + + try { + underTest.hasNext(); + fail("expect npe on use of iterator after release"); + } catch (NullPointerException expected) {} + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/NegativeQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/NegativeQueueTest.java new file mode 100644 index 0000000000..1401b35efb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/NegativeQueueTest.java @@ -0,0 +1,421 @@ +/** + * 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.broker.region.cursors; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.AutoFailTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.StorePendingQueueMessageStoragePolicy; +import org.apache.activemq.usage.MemoryUsage; +import org.apache.activemq.usage.StoreUsage; +import org.apache.activemq.usage.SystemUsage; +import org.apache.activemq.usage.TempUsage; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Modified CursorSupport Unit test to reproduce the negative queue issue. + * + * Keys to reproducing: + * 1) Consecutive queues with listener on first sending to second queue + * 2) Push each queue to the memory limit + * This seems to help reproduce the issue more consistently, but + * we have seen times in our production environment where the + * negative queue can occur without. Our memory limits are + * very high in production and it still happens in varying + * frequency. + * 3) Prefetch + * Lowering the prefetch down to 10 and below seems to help + * reduce occurrences. + * 4) # of consumers per queue + * The issue occurs less with fewer consumers + * + * Things that do not affect reproduction: + * 1) Spring - we use spring in our production applications, but this test case works + * with or without it. + * 2) transacted + * + */ +public class NegativeQueueTest extends AutoFailTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(NegativeQueueTest.class); + + public static SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd,hh:mm:ss:SSS"); + + private static final String QUEUE_1_NAME = "conn.test.queue.1"; + private static final String QUEUE_2_NAME = "conn.test.queue.2"; + + private static final long QUEUE_MEMORY_LIMIT = 2097152; + private static final long MEMORY_USAGE = 400000000; + private static final long TEMP_USAGE = 200000000; + private static final long STORE_USAGE = 1000000000; + // ensure we exceed the cache 70% + private static final int MESSAGE_COUNT = 2100; + + protected static final boolean TRANSACTED = true; + protected static final boolean DEBUG = true; + protected static int NUM_CONSUMERS = 20; + protected static int PREFETCH_SIZE = 1000; + + protected BrokerService broker; + protected String bindAddress = "tcp://localhost:0"; + + public void testWithDefaultPrefetch() throws Exception{ + PREFETCH_SIZE = 1000; + NUM_CONSUMERS = 20; + blastAndConsume(); + } + + public void x_testWithDefaultPrefetchFiveConsumers() throws Exception{ + PREFETCH_SIZE = 1000; + NUM_CONSUMERS = 5; + blastAndConsume(); + } + + public void x_testWithDefaultPrefetchTwoConsumers() throws Exception{ + PREFETCH_SIZE = 1000; + NUM_CONSUMERS = 2; + blastAndConsume(); + } + + public void testWithDefaultPrefetchOneConsumer() throws Exception{ + PREFETCH_SIZE = 1000; + NUM_CONSUMERS = 1; + blastAndConsume(); + } + + public void testWithMediumPrefetch() throws Exception{ + PREFETCH_SIZE = 50; + NUM_CONSUMERS = 20; + blastAndConsume(); + } + + public void x_testWithSmallPrefetch() throws Exception{ + PREFETCH_SIZE = 10; + NUM_CONSUMERS = 20; + blastAndConsume(); + } + + public void testWithNoPrefetch() throws Exception{ + PREFETCH_SIZE = 1; + NUM_CONSUMERS = 20; + blastAndConsume(); + } + + public void blastAndConsume() throws Exception { + LOG.info(getName()); + ConnectionFactory factory = createConnectionFactory(); + + //get proxy queues for statistics lookups + Connection proxyConnection = factory.createConnection(); + proxyConnection.start(); + Session proxySession = proxyConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final QueueViewMBean proxyQueue1 = getProxyToQueueViewMBean(proxySession.createQueue(QUEUE_1_NAME)); + final QueueViewMBean proxyQueue2 = getProxyToQueueViewMBean(proxySession.createQueue(QUEUE_2_NAME)); + + // LOAD THE QUEUE + Connection producerConnection = factory.createConnection(); + producerConnection.start(); + Session session = producerConnection.createSession(TRANSACTED, Session.AUTO_ACKNOWLEDGE); + Destination queue = session.createQueue(QUEUE_1_NAME); + MessageProducer producer = session.createProducer(queue); + List senderList = new ArrayList(); + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage msg = session.createTextMessage(i + " " + formatter.format(new Date())); + senderList.add(msg); + producer.send(msg); + if(TRANSACTED) session.commit(); + if(DEBUG && i%100 == 0){ + int index = (i/100)+1; + System.out.print(index-((index/10)*10)); + } + } + + //get access to the Queue info + if(DEBUG){ + System.out.println(""); + System.out.println("Queue1 Size = "+proxyQueue1.getQueueSize()); + System.out.println("Queue1 Memory % Used = "+proxyQueue1.getMemoryPercentUsage()); + System.out.println("Queue1 Memory Available = "+proxyQueue1.getMemoryLimit()); + } + + // FLUSH THE QUEUE + final CountDownLatch latch1 = new CountDownLatch(1); + final CountDownLatch latch2 = new CountDownLatch(1); + Connection[] consumerConnections1 = new Connection[NUM_CONSUMERS]; + List consumerList1 = new ArrayList(); + Connection[] consumerConnections2 = new Connection[NUM_CONSUMERS]; + Connection[] producerConnections2 = new Connection[NUM_CONSUMERS]; + List consumerList2 = new ArrayList(); + + for(int ix=0; ix consumerList; + private final CountDownLatch latch; + private final Session consumerSession; + private Session producerSession; + private MessageProducer producer; + + public SessionAwareMessageListener(Session consumerSession, CountDownLatch latch, List consumerList){ + this(null, consumerSession, null, latch, consumerList); + } + + public SessionAwareMessageListener(Connection producerConnection, Session consumerSession, String outQueueName, + CountDownLatch latch, List consumerList){ + this.consumerList = consumerList; + this.latch = latch; + this.consumerSession = consumerSession; + + if(producerConnection != null){ + try { + producerSession = producerConnection.createSession(TRANSACTED, Session.AUTO_ACKNOWLEDGE); + Destination queue = producerSession.createQueue(outQueueName); + producer = producerSession.createProducer(queue); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onMessage(Message msg) { + try { + if(producer == null){ + // sleep to act as a slow consumer + // which will force a mix of direct and polled dispatching + // using the cursor on the broker + Thread.sleep(50); + }else{ + producer.send(msg); + if(TRANSACTED) producerSession.commit(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + synchronized(consumerList){ + consumerList.add(msg); + if(DEBUG && consumerList.size()%100 == 0) { + int index = consumerList.size()/100; + System.out.print(index-((index/10)*10)); + } + if (consumerList.size() == MESSAGE_COUNT) { + latch.countDown(); + } + } + if(TRANSACTED){ + try { + consumerSession.commit(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/OrderPendingListTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/OrderPendingListTest.java new file mode 100644 index 0000000000..79d7e6c36e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/OrderPendingListTest.java @@ -0,0 +1,444 @@ +/** + * 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.broker.region.cursors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.MessageReference; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.util.IdGenerator; +import org.junit.Test; + +public class OrderPendingListTest { + + @Test + public void testAddMessageFirst() throws Exception { + + OrderedPendingList list = new OrderedPendingList(); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + + Iterator iter = list.iterator(); + int lastId = list.size(); + while (iter.hasNext()) { + assertEquals(lastId--, iter.next().getMessageId().getProducerSequenceId()); + } + } + + @Test + public void testAddMessageLast() throws Exception { + + OrderedPendingList list = new OrderedPendingList(); + + list.addMessageLast(new TestMessageReference(1)); + list.addMessageLast(new TestMessageReference(2)); + list.addMessageLast(new TestMessageReference(3)); + list.addMessageLast(new TestMessageReference(4)); + list.addMessageLast(new TestMessageReference(5)); + + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + + Iterator iter = list.iterator(); + int lastId = 1; + while (iter.hasNext()) { + assertEquals(lastId++, iter.next().getMessageId().getProducerSequenceId()); + } + } + + @Test + public void testClear() throws Exception { + OrderedPendingList list = new OrderedPendingList(); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertFalse(list.isEmpty()); + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + + list.clear(); + + assertTrue(list.isEmpty()); + assertTrue(list.size() == 0); + assertEquals(0, list.getAsList().size()); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageLast(new TestMessageReference(2)); + list.addMessageLast(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageLast(new TestMessageReference(5)); + + assertFalse(list.isEmpty()); + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + } + + @Test + public void testIsEmpty() throws Exception { + OrderedPendingList list = new OrderedPendingList(); + assertTrue(list.isEmpty()); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertFalse(list.isEmpty()); + list.clear(); + assertTrue(list.isEmpty()); + } + + @Test + public void testSize() { + OrderedPendingList list = new OrderedPendingList(); + assertTrue(list.isEmpty()); + + assertTrue(list.size() == 0); + list.addMessageFirst(new TestMessageReference(1)); + assertTrue(list.size() == 1); + list.addMessageLast(new TestMessageReference(2)); + assertTrue(list.size() == 2); + list.addMessageFirst(new TestMessageReference(3)); + assertTrue(list.size() == 3); + list.addMessageLast(new TestMessageReference(4)); + assertTrue(list.size() == 4); + list.addMessageFirst(new TestMessageReference(5)); + assertTrue(list.size() == 5); + + assertFalse(list.isEmpty()); + list.clear(); + assertTrue(list.isEmpty()); + assertTrue(list.size() == 0); + } + + @Test + public void testRemove() throws Exception { + + OrderedPendingList list = new OrderedPendingList(); + + TestMessageReference toRemove = new TestMessageReference(6); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + + list.addMessageLast(toRemove); + list.remove(toRemove); + + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + + list.remove(toRemove); + + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + + Iterator iter = list.iterator(); + int lastId = list.size(); + while (iter.hasNext()) { + assertEquals(lastId--, iter.next().getMessageId().getProducerSequenceId()); + } + + list.remove(null); + } + + @Test + public void testContains() throws Exception { + + OrderedPendingList list = new OrderedPendingList(); + + TestMessageReference toRemove = new TestMessageReference(6); + + assertFalse(list.contains(toRemove)); + assertFalse(list.contains(null)); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + + list.addMessageLast(toRemove); + assertTrue(list.size() == 6); + assertTrue(list.contains(toRemove)); + list.remove(toRemove); + assertFalse(list.contains(toRemove)); + + assertTrue(list.size() == 5); + assertEquals(5, list.getAsList().size()); + } + + @Test + public void testValues() throws Exception { + + OrderedPendingList list = new OrderedPendingList(); + + TestMessageReference toRemove = new TestMessageReference(6); + + assertFalse(list.contains(toRemove)); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + Collection values = list.values(); + assertEquals(5, values.size()); + + for (MessageReference msg : values) { + assertTrue(values.contains(msg)); + } + + assertFalse(values.contains(toRemove)); + + list.addMessageLast(toRemove); + values = list.values(); + assertEquals(6, values.size()); + for (MessageReference msg : values) { + assertTrue(values.contains(msg)); + } + + assertTrue(values.contains(toRemove)); + } + + @Test + public void testAddAll() throws Exception { + OrderedPendingList list = new OrderedPendingList(); + TestPendingList source = new TestPendingList(); + + source.addMessageFirst(new TestMessageReference(1)); + source.addMessageFirst(new TestMessageReference(2)); + source.addMessageFirst(new TestMessageReference(3)); + source.addMessageFirst(new TestMessageReference(4)); + source.addMessageFirst(new TestMessageReference(5)); + + assertTrue(list.isEmpty()); + assertEquals(5, source.size()); + list.addAll(source); + assertEquals(5, list.size()); + + for (MessageReference message : source) { + assertTrue(list.contains(message)); + } + + list.addAll(null); + } + + static class TestPendingList implements PendingList { + + private final LinkedList theList = new LinkedList(); + + @Override + public boolean isEmpty() { + return theList.isEmpty(); + } + + @Override + public void clear() { + theList.clear(); + } + + @Override + public PendingNode addMessageFirst(MessageReference message) { + theList.addFirst(message); + return new PendingNode(null, message); + } + + @Override + public PendingNode addMessageLast(MessageReference message) { + theList.addLast(message); + return new PendingNode(null, message); + } + + @Override + public PendingNode remove(MessageReference message) { + if (theList.remove(message)) { + return new PendingNode(null, message); + } else { + return null; + } + } + + @Override + public int size() { + return theList.size(); + } + + @Override + public Iterator iterator() { + return theList.iterator(); + } + + @Override + public boolean contains(MessageReference message) { + return theList.contains(message); + } + + @Override + public Collection values() { + return theList; + } + + @Override + public void addAll(PendingList pendingList) { + for(MessageReference messageReference : pendingList) { + theList.add(messageReference); + } + } + + @Override + public MessageReference get(MessageId messageId) { + for(MessageReference messageReference : theList) { + if (messageReference.getMessageId().equals(messageId)) { + return messageReference; + } + } + return null; + } + } + + static class TestMessageReference implements MessageReference { + + private static final IdGenerator id = new IdGenerator(); + + private MessageId messageId; + private int referenceCount = 0; + + public TestMessageReference(int sequenceId) { + messageId = new MessageId(id.generateId() + ":1", sequenceId); + } + + @Override + public MessageId getMessageId() { + return messageId; + } + + @Override + public Message getMessageHardRef() { + return null; + } + + @Override + public Message getMessage() { + return null; + } + + @Override + public boolean isPersistent() { + return false; + } + + @Override + public Destination getRegionDestination() { + return null; + } + + @Override + public int getRedeliveryCounter() { + return 0; + } + + @Override + public void incrementRedeliveryCounter() { + } + + @Override + public int getReferenceCount() { + return this.referenceCount; + } + + @Override + public int incrementReferenceCount() { + return this.referenceCount++; + } + + @Override + public int decrementReferenceCount() { + return this.referenceCount--; + } + + @Override + public ConsumerId getTargetConsumerId() { + return null; + } + + @Override + public int getSize() { + return 1; + } + + @Override + public long getExpiration() { + return 0; + } + + @Override + public String getGroupID() { + return null; + } + + @Override + public int getGroupSequence() { + return 0; + } + + @Override + public boolean isExpired() { + return false; + } + + @Override + public boolean isDropped() { + return false; + } + + @Override + public boolean isAdvisory() { + return false; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/PrioritizedPendingListTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/PrioritizedPendingListTest.java new file mode 100644 index 0000000000..6c40239b8a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/PrioritizedPendingListTest.java @@ -0,0 +1,303 @@ +/** + * 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.broker.region.cursors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Iterator; + +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.MessageReference; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.util.IdGenerator; +import org.junit.Test; + +public class PrioritizedPendingListTest { + + @Test + public void testAddMessageFirst() { + PrioritizedPendingList list = new PrioritizedPendingList(); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertTrue(list.size() == 5); + + Iterator iter = list.iterator(); + int lastId = list.size(); + while (iter.hasNext()) { + assertEquals(lastId--, iter.next().getMessageId().getProducerSequenceId()); + } + } + + @Test + public void testAddMessageLast() { + + PrioritizedPendingList list = new PrioritizedPendingList(); + + list.addMessageLast(new TestMessageReference(1)); + list.addMessageLast(new TestMessageReference(2)); + list.addMessageLast(new TestMessageReference(3)); + list.addMessageLast(new TestMessageReference(4)); + list.addMessageLast(new TestMessageReference(5)); + + assertTrue(list.size() == 5); + + Iterator iter = list.iterator(); + int lastId = 1; + while (iter.hasNext()) { + assertEquals(lastId++, iter.next().getMessageId().getProducerSequenceId()); + } + } + + @Test + public void testClear() { + PrioritizedPendingList list = new PrioritizedPendingList(); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertFalse(list.isEmpty()); + assertTrue(list.size() == 5); + + list.clear(); + + assertTrue(list.isEmpty()); + assertTrue(list.size() == 0); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageLast(new TestMessageReference(2)); + list.addMessageLast(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageLast(new TestMessageReference(5)); + + assertFalse(list.isEmpty()); + assertTrue(list.size() == 5); + } + + @Test + public void testIsEmpty() { + PrioritizedPendingList list = new PrioritizedPendingList(); + assertTrue(list.isEmpty()); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertFalse(list.isEmpty()); + list.clear(); + assertTrue(list.isEmpty()); + } + + @Test + public void testRemove() { + PrioritizedPendingList list = new PrioritizedPendingList(); + + TestMessageReference toRemove = new TestMessageReference(6); + + list.addMessageFirst(new TestMessageReference(1)); + list.addMessageFirst(new TestMessageReference(2)); + list.addMessageFirst(new TestMessageReference(3)); + list.addMessageFirst(new TestMessageReference(4)); + list.addMessageFirst(new TestMessageReference(5)); + + assertTrue(list.size() == 5); + + list.addMessageLast(toRemove); + list.remove(toRemove); + + assertTrue(list.size() == 5); + + list.remove(toRemove); + + assertTrue(list.size() == 5); + + Iterator iter = list.iterator(); + int lastId = list.size(); + while (iter.hasNext()) { + assertEquals(lastId--, iter.next().getMessageId().getProducerSequenceId()); + } + + list.remove(null); + } + + @Test + public void testSize() { + PrioritizedPendingList list = new PrioritizedPendingList(); + assertTrue(list.isEmpty()); + + assertTrue(list.size() == 0); + list.addMessageFirst(new TestMessageReference(1)); + assertTrue(list.size() == 1); + list.addMessageLast(new TestMessageReference(2)); + assertTrue(list.size() == 2); + list.addMessageFirst(new TestMessageReference(3)); + assertTrue(list.size() == 3); + list.addMessageLast(new TestMessageReference(4)); + assertTrue(list.size() == 4); + list.addMessageFirst(new TestMessageReference(5)); + assertTrue(list.size() == 5); + + assertFalse(list.isEmpty()); + list.clear(); + assertTrue(list.isEmpty()); + assertTrue(list.size() == 0); + } + + @Test + public void testPrioritization() { + PrioritizedPendingList list = new PrioritizedPendingList(); + + list.addMessageFirst(new TestMessageReference(1, 5)); + list.addMessageFirst(new TestMessageReference(2, 4)); + list.addMessageFirst(new TestMessageReference(3, 3)); + list.addMessageFirst(new TestMessageReference(4, 2)); + list.addMessageFirst(new TestMessageReference(5, 1)); + + assertTrue(list.size() == 5); + + Iterator iter = list.iterator(); + int lastId = list.size(); + while (iter.hasNext()) { + assertEquals(lastId--, iter.next().getMessage().getPriority()); + } + } + + static class TestMessageReference implements MessageReference { + + private static final IdGenerator id = new IdGenerator(); + + private Message message; + private MessageId messageId; + private int referenceCount = 0; + + public TestMessageReference(int sequenceId) { + messageId = new MessageId(id.generateId() + ":1", sequenceId); + message = new ActiveMQMessage(); + message.setPriority((byte) javax.jms.Message.DEFAULT_PRIORITY); + } + + public TestMessageReference(int sequenceId, int priority) { + messageId = new MessageId(id.generateId() + ":1", sequenceId); + message = new ActiveMQMessage(); + message.setPriority((byte) priority); + } + + @Override + public MessageId getMessageId() { + return messageId; + } + + @Override + public Message getMessageHardRef() { + return null; + } + + @Override + public Message getMessage() { + return message; + } + + @Override + public boolean isPersistent() { + return false; + } + + @Override + public Destination getRegionDestination() { + return null; + } + + @Override + public int getRedeliveryCounter() { + return 0; + } + + @Override + public void incrementRedeliveryCounter() { + } + + @Override + public int getReferenceCount() { + return this.referenceCount; + } + + @Override + public int incrementReferenceCount() { + return this.referenceCount++; + } + + @Override + public int decrementReferenceCount() { + return this.referenceCount--; + } + + @Override + public ConsumerId getTargetConsumerId() { + return null; + } + + @Override + public int getSize() { + return 1; + } + + @Override + public long getExpiration() { + return 0; + } + + @Override + public String getGroupID() { + return null; + } + + @Override + public int getGroupSequence() { + return 0; + } + + @Override + public boolean isExpired() { + return false; + } + + @Override + public boolean isDropped() { + return false; + } + + @Override + public boolean isAdvisory() { + return false; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreBasedCursorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreBasedCursorTest.java new file mode 100644 index 0000000000..a330723060 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreBasedCursorTest.java @@ -0,0 +1,160 @@ +/** + * 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.broker.region.cursors; + +/** + * A StoreBasedCursorTest + * + */ + +import java.util.Date; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.usage.SystemUsage; + +public class StoreBasedCursorTest extends TestCase { + protected String bindAddress = "tcp://localhost:60706"; + BrokerService broker; + ActiveMQConnectionFactory factory; + Connection connection; + Session session; + Queue queue; + int messageSize = 1024; + // actual message is messageSize*2, and 4*MessageSize would allow 2 messages be delivered, but the flush of the cache is async so the flush + // triggered on 2nd message maxing out the usage may not be in effect for the 3rd message to succeed. Making the memory usage more lenient + // gives the usageChange listener in the cursor an opportunity to kick in. + int memoryLimit = 12 * messageSize; + + protected void setUp() throws Exception { + super.setUp(); + if (broker == null) { + broker = new BrokerService(); + broker.setAdvisorySupport(false); + } + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + broker = null; + } + } + + protected void start() throws Exception { + broker.start(); + factory = new ActiveMQConnectionFactory("vm://localhost?jms.alwaysSyncSend=true"); + factory.setWatchTopicAdvisories(false); + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + queue = session.createQueue("QUEUE." + this.getClass().getName()); + } + + protected void stop() throws Exception { + session.close(); + connection.close(); + broker.stop(); + broker = null; + } + + protected void configureBroker(long memoryLimit, long systemLimit) throws Exception { + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector(bindAddress); + broker.setPersistent(true); + + SystemUsage systemUsage = broker.getSystemUsage(); + systemUsage.setSendFailIfNoSpace(true); + systemUsage.getMemoryUsage().setLimit(systemLimit); + + PolicyEntry policy = new PolicyEntry(); + policy.setProducerFlowControl(true); + policy.setUseCache(true); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + } + + protected String createMessageText(int index) { + StringBuffer buffer = new StringBuffer(messageSize); + buffer.append("Message: " + index + " sent at: " + new Date()); + if (buffer.length() > messageSize) { + return buffer.substring(0, messageSize); + } + for (int i = buffer.length(); i < messageSize; i++) { + buffer.append(' '); + } + return buffer.toString(); + } + + protected void sendMessages(int deliveryMode) throws Exception { + start(); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(deliveryMode); + int i =0; + try { + for (i = 0; i < 200; i++) { + TextMessage message = session.createTextMessage(createMessageText(i)); + producer.send(message); + } + } catch (javax.jms.ResourceAllocationException e) { + e.printStackTrace(); + fail(e.getMessage() + " num msgs = " + i + ". percentUsage = " + broker.getSystemUsage().getMemoryUsage().getPercentUsage()); + } + stop(); + } + + // use QueueStorePrefetch + public void testTwoUsageEqualPersistent() throws Exception { + configureBroker(memoryLimit, memoryLimit); + sendMessages(DeliveryMode.PERSISTENT); + } + + public void testUseCachePersistent() throws Exception { + int limit = memoryLimit / 2; + configureBroker(limit, memoryLimit); + sendMessages(DeliveryMode.PERSISTENT); + } + + public void testMemoryUsageLowPersistent() throws Exception { + configureBroker(memoryLimit, 10 * memoryLimit); + sendMessages(DeliveryMode.PERSISTENT); + } + + // use FilePendingMessageCursor + public void testTwoUsageEqualNonPersistent() throws Exception { + configureBroker(memoryLimit, memoryLimit); + sendMessages(DeliveryMode.NON_PERSISTENT); + } + + public void testMemoryUsageLowNonPersistent() throws Exception { + configureBroker(memoryLimit, 10 * memoryLimit); + sendMessages(DeliveryMode.NON_PERSISTENT); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorJDBCNoDuplicateTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorJDBCNoDuplicateTest.java new file mode 100644 index 0000000000..6b49c8d546 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorJDBCNoDuplicateTest.java @@ -0,0 +1,37 @@ +/** + * 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.broker.region.cursors; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; + +/** + * @author gtully + * @see https://issues.apache.org/activemq/browse/AMQ-2020 + **/ +public class StoreQueueCursorJDBCNoDuplicateTest extends StoreQueueCursorNoDuplicateTest { + + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + PersistenceAdapter persistenceAdapter = new JDBCPersistenceAdapter(); + broker.setPersistenceAdapter(persistenceAdapter); + return broker; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorKahaDBNoDuplicateTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorKahaDBNoDuplicateTest.java new file mode 100644 index 0000000000..11a98d694d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorKahaDBNoDuplicateTest.java @@ -0,0 +1,40 @@ +/** + * 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.broker.region.cursors; + +import java.io.File; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBStore; + +/** + * @author gtully + * @see https://issues.apache.org/activemq/browse/AMQ-2020 + **/ +public class StoreQueueCursorKahaDBNoDuplicateTest extends StoreQueueCursorNoDuplicateTest { + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + PersistenceAdapter persistenceAdapter = new KahaDBStore(); + persistenceAdapter.setDirectory(new File("target/activemq-data/kahadb")); + broker.setPersistenceAdapter(persistenceAdapter); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorLevelDBNoDuplicateTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorLevelDBNoDuplicateTest.java new file mode 100644 index 0000000000..d119d506ed --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorLevelDBNoDuplicateTest.java @@ -0,0 +1,40 @@ +/** + * 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.broker.region.cursors; + +import org.apache.activeio.journal.active.JournalImpl; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.store.journal.JournalPersistenceAdapter; + +import java.io.File; + +/** + * @author gtully + * @see https://issues.apache.org/activemq/browse/AMQ-2020 + **/ +public class StoreQueueCursorLevelDBNoDuplicateTest extends StoreQueueCursorNoDuplicateTest { + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + LevelDBStore store = new LevelDBStore(); + store.setDirectory(new File("target/activemq-data/leveldb")); + broker.setPersistenceAdapter(store); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorMemoryNoDuplicateTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorMemoryNoDuplicateTest.java new file mode 100644 index 0000000000..a62748a86b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorMemoryNoDuplicateTest.java @@ -0,0 +1,33 @@ +/** + * 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.broker.region.cursors; + +import org.apache.activemq.broker.BrokerService; + +/** + * @author gtully + * @see https://issues.apache.org/activemq/browse/AMQ-2020 + **/ +public class StoreQueueCursorMemoryNoDuplicateTest extends StoreQueueCursorNoDuplicateTest { + + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.setPersistent(false); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorNoDuplicateTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorNoDuplicateTest.java new file mode 100644 index 0000000000..2406e88b94 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorNoDuplicateTest.java @@ -0,0 +1,133 @@ +/** + * 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.broker.region.cursors; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.MessageReference; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.store.MessageStore; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.usage.SystemUsage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author gtully + * https://issues.apache.org/activemq/browse/AMQ-2020 + **/ +public class StoreQueueCursorNoDuplicateTest extends TestCase { + static final Logger LOG = LoggerFactory.getLogger(StoreQueueCursorNoDuplicateTest.class); + ActiveMQQueue destination = new ActiveMQQueue("queue-" + + StoreQueueCursorNoDuplicateTest.class.getSimpleName()); + BrokerService brokerService; + + final static String mesageIdRoot = "11111:22222:0:"; + final int messageBytesSize = 1024; + final String text = new String(new byte[messageBytesSize]); + + protected int count = 6; + + @Override + public void setUp() throws Exception { + brokerService = createBroker(); + brokerService.setUseJmx(false); + brokerService.deleteAllMessages(); + brokerService.start(); + } + + protected BrokerService createBroker() throws Exception { + return new BrokerService(); + } + + @Override + public void tearDown() throws Exception { + brokerService.stop(); + } + + public void testNoDuplicateAfterCacheFullAndReadPast() throws Exception { + final PersistenceAdapter persistenceAdapter = brokerService + .getPersistenceAdapter(); + final MessageStore queueMessageStore = persistenceAdapter + .createQueueMessageStore(destination); + final ConsumerInfo consumerInfo = new ConsumerInfo(); + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + consumerInfo.setExclusive(true); + + final Queue queue = new Queue(brokerService, destination, + queueMessageStore, destinationStatistics, null); + + queueMessageStore.start(); + queueMessageStore.registerIndexListener(null); + + QueueStorePrefetch underTest = new QueueStorePrefetch(queue, brokerService.getBroker()); + SystemUsage systemUsage = new SystemUsage(); + // ensure memory limit is reached + systemUsage.getMemoryUsage().setLimit(messageBytesSize * (count + 2)); + underTest.setSystemUsage(systemUsage); + underTest.setEnableAudit(false); + underTest.start(); + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + final ConnectionContext contextNotInTx = new ConnectionContext(); + for (int i = 0; i < count; i++) { + ActiveMQTextMessage msg = getMessage(i); + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + + queueMessageStore.addMessage(contextNotInTx, msg); + underTest.addMessageLast(msg); + } + + assertTrue("cache is disabled as limit reached", !underTest.isCacheEnabled()); + int dequeueCount = 0; + + underTest.setMaxBatchSize(2); + underTest.reset(); + while (underTest.hasNext() && dequeueCount < count) { + MessageReference ref = underTest.next(); + ref.decrementReferenceCount(); + underTest.remove(); + LOG.info("Received message: {} with body: {}", + ref.getMessageId(), ((ActiveMQTextMessage)ref.getMessage()).getText()); + assertEquals(dequeueCount++, ref.getMessageId().getProducerSequenceId()); + } + underTest.release(); + assertEquals(count, dequeueCount); + } + + private ActiveMQTextMessage getMessage(int i) throws Exception { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + MessageId id = new MessageId(mesageIdRoot + i); + id.setBrokerSequenceId(i); + id.setProducerSequenceId(i); + message.setMessageId(id); + message.setDestination(destination); + message.setPersistent(true); + message.setResponseRequired(true); + message.setText("Msg:" + i + " " + text); + assertEquals(message.getMessageId().getProducerSequenceId(), i); + return message; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorOrderTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorOrderTest.java new file mode 100644 index 0000000000..f8fab10a13 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/region/cursors/StoreQueueCursorOrderTest.java @@ -0,0 +1,517 @@ +/** + * 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.broker.region.cursors; + +import java.io.IOException; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.concurrent.atomic.AtomicLong; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.MessageReference; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.store.AbstractMessageStore; +import org.apache.activemq.store.MessageRecoveryListener; +import org.apache.activemq.usage.SystemUsage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class StoreQueueCursorOrderTest { + private static final Logger LOG = LoggerFactory.getLogger(StoreQueueCursorOrderTest.class); + + ActiveMQQueue destination = new ActiveMQQueue("queue-" + + StoreQueueCursorOrderTest.class.getSimpleName()); + BrokerService brokerService; + + final static String mesageIdRoot = "11111:22222:0:"; + final int messageBytesSize = 1024; + final String text = new String(new byte[messageBytesSize]); + + @Before + public void setUp() throws Exception { + brokerService = createBroker(); + brokerService.setUseJmx(false); + brokerService.deleteAllMessages(); + brokerService.start(); + } + + protected BrokerService createBroker() throws Exception { + return new BrokerService(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + } + + @Test + public void tesBlockedFuture() throws Exception { + final int count = 2; + final Message[] messages = new Message[count]; + final TestMessageStore queueMessageStore = new TestMessageStore(messages, destination); + final ConsumerInfo consumerInfo = new ConsumerInfo(); + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + consumerInfo.setExclusive(true); + + final Queue queue = new Queue(brokerService, destination, + queueMessageStore, destinationStatistics, null); + + queueMessageStore.start(); + queueMessageStore.registerIndexListener(null); + + QueueStorePrefetch underTest = new QueueStorePrefetch(queue, brokerService.getBroker()); + SystemUsage systemUsage = new SystemUsage(); + // ensure memory limit is reached + systemUsage.getMemoryUsage().setLimit(messageBytesSize * 1); + underTest.setSystemUsage(systemUsage); + underTest.setEnableAudit(false); + underTest.start(); + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + ActiveMQTextMessage msg = getMessage(0); + messages[1] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.setRecievedByDFBridge(true); + FutureTask future = new FutureTask(new Runnable() { + @Override + public void run() { + } + }, 2l) {}; + msg.getMessageId().setFutureOrSequenceLong(future); + underTest.addMessageLast(msg); + + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + // second message will flip the cache but will be stored before the future task + msg = getMessage(1); + messages[0] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.getMessageId().setFutureOrSequenceLong(1l); + underTest.addMessageLast(msg); + + + assertTrue("cache is disabled as limit reached", !underTest.isCacheEnabled()); + assertEquals("setBatch unset", 0l, queueMessageStore.batch.get()); + + int dequeueCount = 0; + + underTest.setMaxBatchSize(2); + underTest.reset(); + while (underTest.hasNext() && dequeueCount < count) { + MessageReference ref = underTest.next(); + ref.decrementReferenceCount(); + underTest.remove(); + LOG.info("Received message: {} with body: {}", + ref.getMessageId(), ((ActiveMQTextMessage)ref.getMessage()).getText()); + assertEquals(dequeueCount++, ref.getMessageId().getProducerSequenceId()); + } + underTest.release(); + assertEquals(count, dequeueCount); + } + + @Test + public void testNoSetBatchWithUnOrderedFutureCurrentSync() throws Exception { + final int count = 2; + final Message[] messages = new Message[count]; + final TestMessageStore queueMessageStore = new TestMessageStore(messages, destination); + final ConsumerInfo consumerInfo = new ConsumerInfo(); + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + consumerInfo.setExclusive(true); + + final Queue queue = new Queue(brokerService, destination, + queueMessageStore, destinationStatistics, null); + + queueMessageStore.start(); + queueMessageStore.registerIndexListener(null); + + QueueStorePrefetch underTest = new QueueStorePrefetch(queue, brokerService.getBroker()); + SystemUsage systemUsage = new SystemUsage(); + // ensure memory limit is reached + systemUsage.getMemoryUsage().setLimit(messageBytesSize * 1); + underTest.setSystemUsage(systemUsage); + underTest.setEnableAudit(false); + underTest.start(); + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + ActiveMQTextMessage msg = getMessage(0); + messages[1] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.setRecievedByDFBridge(true); + final ActiveMQTextMessage msgRef = msg; + FutureTask future = new FutureTask(new Runnable() { + @Override + public void run() { + msgRef.getMessageId().setFutureOrSequenceLong(1l); + } + }, 1l) {}; + msg.getMessageId().setFutureOrSequenceLong(future); + Executors.newSingleThreadExecutor().submit(future); + underTest.addMessageLast(msg); + + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + // second message will flip the cache but will be stored before the future task + msg = getMessage(1); + messages[0] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.getMessageId().setFutureOrSequenceLong(1l); + underTest.addMessageLast(msg); + + + assertTrue("cache is disabled as limit reached", !underTest.isCacheEnabled()); + assertEquals("setBatch unset", 0l, queueMessageStore.batch.get()); + + int dequeueCount = 0; + + underTest.setMaxBatchSize(2); + underTest.reset(); + while (underTest.hasNext() && dequeueCount < count) { + MessageReference ref = underTest.next(); + ref.decrementReferenceCount(); + underTest.remove(); + LOG.info("Received message: {} with body: {}", + ref.getMessageId(), ((ActiveMQTextMessage)ref.getMessage()).getText()); + assertEquals(dequeueCount++, ref.getMessageId().getProducerSequenceId()); + } + underTest.release(); + assertEquals(count, dequeueCount); + } + + @Test + public void testSetBatchWithOrderedFutureCurrentFuture() throws Exception { + final int count = 2; + final Message[] messages = new Message[count]; + final TestMessageStore queueMessageStore = new TestMessageStore(messages, destination); + final ConsumerInfo consumerInfo = new ConsumerInfo(); + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + consumerInfo.setExclusive(true); + + final Queue queue = new Queue(brokerService, destination, + queueMessageStore, destinationStatistics, null); + + queueMessageStore.start(); + queueMessageStore.registerIndexListener(null); + + QueueStorePrefetch underTest = new QueueStorePrefetch(queue, brokerService.getBroker()); + SystemUsage systemUsage = new SystemUsage(); + // ensure memory limit is reached + systemUsage.getMemoryUsage().setLimit(messageBytesSize * 1); + underTest.setSystemUsage(systemUsage); + underTest.setEnableAudit(false); + underTest.start(); + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + ActiveMQTextMessage msg = getMessage(0); + messages[0] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.setRecievedByDFBridge(true); + final ActiveMQTextMessage msgRef = msg; + FutureTask future = new FutureTask(new Runnable() { + @Override + public void run() { + msgRef.getMessageId().setFutureOrSequenceLong(0l); + } + }, 0l) {}; + msg.getMessageId().setFutureOrSequenceLong(future); + Executors.newSingleThreadExecutor().submit(future); + underTest.addMessageLast(msg); + + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + // second message will flip the cache but will be stored before the future task + msg = getMessage(1); + messages[1] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.setRecievedByDFBridge(true); + final ActiveMQTextMessage msgRe2f = msg; + FutureTask future2 = new FutureTask(new Runnable() { + @Override + public void run() { + msgRe2f.getMessageId().setFutureOrSequenceLong(1l); + } + }, 1l) {}; + msg.getMessageId().setFutureOrSequenceLong(future2); + Executors.newSingleThreadExecutor().submit(future2); + underTest.addMessageLast(msg); + + + assertTrue("cache is disabled as limit reached", !underTest.isCacheEnabled()); + assertEquals("setBatch set", 1l, queueMessageStore.batch.get()); + + int dequeueCount = 0; + + underTest.setMaxBatchSize(2); + underTest.reset(); + while (underTest.hasNext() && dequeueCount < count) { + MessageReference ref = underTest.next(); + ref.decrementReferenceCount(); + underTest.remove(); + LOG.info("Received message: {} with body: {}", + ref.getMessageId(), ((ActiveMQTextMessage)ref.getMessage()).getText()); + assertEquals(dequeueCount++, ref.getMessageId().getProducerSequenceId()); + } + underTest.release(); + assertEquals(count, dequeueCount); + } + + @Test + public void testSetBatchWithFuture() throws Exception { + final int count = 4; + final Message[] messages = new Message[count]; + final TestMessageStore queueMessageStore = new TestMessageStore(messages, destination); + final ConsumerInfo consumerInfo = new ConsumerInfo(); + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + consumerInfo.setExclusive(true); + + final Queue queue = new Queue(brokerService, destination, + queueMessageStore, destinationStatistics, null); + + queueMessageStore.start(); + queueMessageStore.registerIndexListener(null); + + QueueStorePrefetch underTest = new QueueStorePrefetch(queue, brokerService.getBroker()); + SystemUsage systemUsage = new SystemUsage(); + // ensure memory limit is reached + systemUsage.getMemoryUsage().setLimit(messageBytesSize * (count + 6)); + underTest.setSystemUsage(systemUsage); + underTest.setEnableAudit(false); + underTest.start(); + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + ActiveMQTextMessage msg = getMessage(0); + messages[0] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.setRecievedByDFBridge(true); + final ActiveMQTextMessage msgRef = msg; + FutureTask future0 = new FutureTask(new Runnable() { + @Override + public void run() { + msgRef.getMessageId().setFutureOrSequenceLong(0l); + } + }, 0l) {}; + msg.getMessageId().setFutureOrSequenceLong(future0); + underTest.addMessageLast(msg); + Executors.newSingleThreadExecutor().submit(future0); + + + msg = getMessage(1); + messages[3] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.setRecievedByDFBridge(true); + final ActiveMQTextMessage msgRef1 = msg; + FutureTask future1 = new FutureTask(new Runnable() { + @Override + public void run() { + msgRef1.getMessageId().setFutureOrSequenceLong(3l); + } + }, 3l) {}; + msg.getMessageId().setFutureOrSequenceLong(future1); + underTest.addMessageLast(msg); + + + msg = getMessage(2); + messages[1] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.getMessageId().setFutureOrSequenceLong(1l); + underTest.addMessageLast(msg); + + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + // out of order future + Executors.newSingleThreadExecutor().submit(future1); + + // sync add to flip cache + msg = getMessage(3); + messages[2] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.getMessageId().setFutureOrSequenceLong(3l); + underTest.addMessageLast(msg); + + + assertTrue("cache is disabled as limit reached", !underTest.isCacheEnabled()); + assertEquals("setBatch set", 2l, queueMessageStore.batch.get()); + + int dequeueCount = 0; + + underTest.setMaxBatchSize(count); + underTest.reset(); + while (underTest.hasNext() && dequeueCount < count) { + MessageReference ref = underTest.next(); + ref.decrementReferenceCount(); + underTest.remove(); + LOG.info("Received message: {} with body: {}", + ref.getMessageId(), ((ActiveMQTextMessage)ref.getMessage()).getText()); + assertEquals(dequeueCount++, ref.getMessageId().getProducerSequenceId()); + } + underTest.release(); + assertEquals(count, dequeueCount); + } + + @Test + public void testSetBatch() throws Exception { + final int count = 3; + final Message[] messages = new Message[count]; + final TestMessageStore queueMessageStore = new TestMessageStore(messages, destination); + final ConsumerInfo consumerInfo = new ConsumerInfo(); + final DestinationStatistics destinationStatistics = new DestinationStatistics(); + consumerInfo.setExclusive(true); + + final Queue queue = new Queue(brokerService, destination, + queueMessageStore, destinationStatistics, null); + + queueMessageStore.start(); + queueMessageStore.registerIndexListener(null); + + QueueStorePrefetch underTest = new QueueStorePrefetch(queue, brokerService.getBroker()); + SystemUsage systemUsage = new SystemUsage(); + // ensure memory limit is reached + systemUsage.getMemoryUsage().setLimit(messageBytesSize * 5); + underTest.setSystemUsage(systemUsage); + underTest.setEnableAudit(false); + underTest.start(); + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + + ActiveMQTextMessage msg = getMessage(0); + messages[0] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.getMessageId().setFutureOrSequenceLong(0l); + underTest.addMessageLast(msg); + + msg = getMessage(1); + messages[1] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.getMessageId().setFutureOrSequenceLong(1l); + underTest.addMessageLast(msg); + + assertTrue("cache enabled", underTest.isUseCache() && underTest.isCacheEnabled()); + + msg = getMessage(2); + messages[2] = msg; + msg.setMemoryUsage(systemUsage.getMemoryUsage()); + msg.getMessageId().setFutureOrSequenceLong(2l); + underTest.addMessageLast(msg); + + + assertTrue("cache is disabled as limit reached", !underTest.isCacheEnabled()); + assertEquals("setBatch set", 2l, queueMessageStore.batch.get()); + + int dequeueCount = 0; + + underTest.setMaxBatchSize(2); + underTest.reset(); + while (underTest.hasNext() && dequeueCount < count) { + MessageReference ref = underTest.next(); + ref.decrementReferenceCount(); + underTest.remove(); + LOG.info("Received message: {} with body: {}", + ref.getMessageId(), ((ActiveMQTextMessage)ref.getMessage()).getText()); + assertEquals(dequeueCount++, ref.getMessageId().getProducerSequenceId()); + } + underTest.release(); + assertEquals(count, dequeueCount); + } + + private ActiveMQTextMessage getMessage(int i) throws Exception { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + MessageId id = new MessageId(mesageIdRoot + i); + id.setBrokerSequenceId(i); + id.setProducerSequenceId(i); + message.setMessageId(id); + message.setDestination(destination); + message.setPersistent(true); + message.setResponseRequired(true); + message.setText("Msg:" + i + " " + text); + assertEquals(message.getMessageId().getProducerSequenceId(), i); + return message; + } + + class TestMessageStore extends AbstractMessageStore { + final Message[] messages; + public AtomicLong batch = new AtomicLong(); + + public TestMessageStore(Message[] messages, ActiveMQDestination dest) { + super(dest); + this.messages = messages; + } + + @Override + public void addMessage(ConnectionContext context, Message message) throws IOException { + + } + + @Override + public Message getMessage(MessageId identity) throws IOException { + return null; + } + + @Override + public void removeMessage(ConnectionContext context, MessageAck ack) throws IOException { + + } + + @Override + public void removeAllMessages(ConnectionContext context) throws IOException { + + } + + @Override + public void recover(MessageRecoveryListener container) throws Exception { + + } + + @Override + public int getMessageCount() throws IOException { + return 0; + } + + @Override + public void resetBatching() { + + } + @Override + public void recoverNextMessages(int maxReturned, MessageRecoveryListener listener) throws Exception { + for (int i=batch.intValue();i list = js.getAllJobs(); + assertEquals(COUNT, list.size()); + latch.await(2, TimeUnit.MINUTES); + //All should messages should have been received by now + assertEquals(COUNT, count.get()); + } + + @Test + public void testCronScheduleWithTtlSet() throws Exception { + + Connection connection = createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + + MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(TimeUnit.MINUTES.toMillis(1)); + TextMessage message = session.createTextMessage("test msg "); + message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "* * * * *"); + + producer.send(message); + producer.close(); + + Thread.sleep(TimeUnit.MINUTES.toMillis(2)); + + assertNotNull(consumer.receiveNoWait()); + assertNull(consumer.receiveNoWait()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JmsSchedulerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JmsSchedulerTest.java new file mode 100644 index 0000000000..0ce584d1e5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JmsSchedulerTest.java @@ -0,0 +1,288 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.util.ProducerThread; +import org.apache.activemq.util.Wait; +import org.junit.Test; + +public class JmsSchedulerTest extends JobSchedulerTestSupport { + + @Test + public void testCron() throws Exception { + final int COUNT = 10; + final AtomicInteger count = new AtomicInteger(); + Connection connection = createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + count.incrementAndGet(); + } + }); + + connection.start(); + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("test msg"); + long time = 1000; + message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "* * * * *"); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 500); + message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, COUNT - 1); + + producer.send(message); + producer.close(); + + Thread.sleep(500); + SchedulerBroker sb = (SchedulerBroker) this.broker.getBroker().getAdaptor(SchedulerBroker.class); + JobScheduler js = sb.getJobScheduler(); + List list = js.getAllJobs(); + assertEquals(1, list.size()); + latch.await(240, TimeUnit.SECONDS); + assertEquals(COUNT, count.get()); + } + + @Test + public void testSchedule() throws Exception { + final int COUNT = 1; + Connection connection = createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + connection.start(); + long time = 5000; + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("test msg"); + + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + + producer.send(message); + producer.close(); + // make sure the message isn't delivered early + Thread.sleep(2000); + assertEquals(latch.getCount(), COUNT); + latch.await(5, TimeUnit.SECONDS); + assertEquals(latch.getCount(), 0); + } + + @Test + public void testTransactedSchedule() throws Exception { + final int COUNT = 1; + Connection connection = createConnection(); + + final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + session.commit(); + } catch (JMSException e) { + e.printStackTrace(); + } + latch.countDown(); + } + }); + + connection.start(); + long time = 5000; + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("test msg"); + + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + + producer.send(message); + session.commit(); + producer.close(); + // make sure the message isn't delivered early + Thread.sleep(2000); + assertEquals(latch.getCount(), COUNT); + latch.await(5, TimeUnit.SECONDS); + assertEquals(latch.getCount(), 0); + } + + @Test + public void testScheduleRepeated() throws Exception { + final int NUMBER = 10; + final AtomicInteger count = new AtomicInteger(); + Connection connection = createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(NUMBER); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + count.incrementAndGet(); + } + }); + + connection.start(); + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("test msg"); + long time = 1000; + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 500); + message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, NUMBER - 1); + producer.send(message); + producer.close(); + assertEquals(latch.getCount(), NUMBER); + latch.await(10, TimeUnit.SECONDS); + assertEquals(0, latch.getCount()); + // wait a little longer - make sure we only get NUMBER of replays + Thread.sleep(1000); + assertEquals(NUMBER, count.get()); + } + + @Test + public void testScheduleRestart() throws Exception { + // send a message + Connection connection = createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.start(); + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("test msg"); + long time = 5000; + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + producer.send(message); + producer.close(); + + //restart broker + broker.stop(); + broker.waitUntilStopped(); + + broker = createBroker(false); + broker.start(); + broker.waitUntilStarted(); + + + // consume the message + connection = createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + Message msg = consumer.receive(5000); + assertNotNull("Didn't receive the message", msg); + + //send another message + producer = session.createProducer(destination); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + producer.send(message); + producer.close(); + } + + @Test + public void testJobSchedulerStoreUsage() throws Exception { + + // Shrink the store limit down so we get the producer to block + broker.getSystemUsage().getJobSchedulerUsage().setLimit(10 * 1024); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final long time = 5000; + final ProducerThread producer = new ProducerThread(sess, destination) { + @Override + protected Message createMessage(int i) throws Exception { + Message message = super.createMessage(i); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + return message; + } + }; + producer.setMessageCount(100); + producer.start(); + + MessageConsumer consumer = sess.createConsumer(destination); + final CountDownLatch latch = new CountDownLatch(100); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + // wait for the producer to block, which should happen immediately, and also wait long + // enough for the delay to elapse. We should see no deliveries as the send should block + // on the first message. + Thread.sleep(10000l); + + assertEquals(100, latch.getCount()); + + // Increase the store limit so the producer unblocks. Everything should enqueue at this point. + broker.getSystemUsage().getJobSchedulerUsage().setLimit(1024 * 1024 * 33); + + // Wait long enough that the messages are enqueued and the delivery delay has elapsed. + Thread.sleep(10000l); + + // Make sure we sent all the messages we expected to send + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return producer.getSentCount() == producer.getMessageCount(); + } + }, 20000l); + + assertEquals("Producer didn't send all messages", producer.getMessageCount(), producer.getSentCount()); + + // Make sure we got all the messages we expected to get + latch.await(20000l, TimeUnit.MILLISECONDS); + + assertEquals("Consumer did not receive all messages.", 0, latch.getCount()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerBrokerShutdownTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerBrokerShutdownTest.java new file mode 100644 index 0000000000..641ee97247 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerBrokerShutdownTest.java @@ -0,0 +1,78 @@ +/** + * 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.broker.scheduler; + +import java.io.File; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.Session; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.ProducerThread; + +public class JobSchedulerBrokerShutdownTest extends EmbeddedBrokerTestSupport { + + @Override + protected BrokerService createBroker() throws Exception { + File schedulerDirectory = new File("target/scheduler"); + + IOHelper.mkdirs(schedulerDirectory); + IOHelper.deleteChildren(schedulerDirectory); + + BrokerService broker = super.createBroker(); + broker.setSchedulerSupport(true); + broker.setDataDirectory("target"); + broker.setSchedulerDirectoryFile(schedulerDirectory); + broker.getSystemUsage().getStoreUsage().setLimit(1 * 512); + broker.deleteAllMessages(); + return broker; + } + + @Override + protected boolean isPersistent() { + return true; + } + + public void testSchedule() throws Exception { + + Connection connection = createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + connection.start(); + final long time = 1000; + + ProducerThread producer = new ProducerThread(session, destination) { + @Override + protected Message createMessage(int i) throws Exception { + Message message = super.createMessage(i); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + return message; + } + }; + + producer.setMessageCount(200); + producer.setDaemon(true); + + producer.start(); + + Thread.sleep(5000); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerJmxManagementTests.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerJmxManagementTests.java new file mode 100644 index 0000000000..b5d2227088 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerJmxManagementTests.java @@ -0,0 +1,155 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.openmbean.TabularData; + +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.jmx.JobSchedulerViewMBean; +import org.apache.activemq.util.Wait; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tests of the JMX JobSchedulerStore management MBean. + */ +public class JobSchedulerJmxManagementTests extends JobSchedulerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(JobSchedulerJmxManagementTests.class); + + @Test + public void testJobSchedulerMBeanIsRegistered() throws Exception { + JobSchedulerViewMBean view = getJobSchedulerMBean(); + assertNotNull(view); + assertTrue(view.getAllJobs().isEmpty()); + } + + @Test + public void testGetNumberOfJobs() throws Exception { + JobSchedulerViewMBean view = getJobSchedulerMBean(); + assertNotNull(view); + assertTrue(view.getAllJobs().isEmpty()); + scheduleMessage(60000, -1, -1); + assertFalse(view.getAllJobs().isEmpty()); + assertEquals(1, view.getAllJobs().size()); + scheduleMessage(60000, -1, -1); + assertEquals(2, view.getAllJobs().size()); + } + + @Test + public void testRemvoeJob() throws Exception { + JobSchedulerViewMBean view = getJobSchedulerMBean(); + assertNotNull(view); + assertTrue(view.getAllJobs().isEmpty()); + scheduleMessage(60000, -1, -1); + assertFalse(view.getAllJobs().isEmpty()); + TabularData jobs = view.getAllJobs(); + assertEquals(1, jobs.size()); + for (Object key : jobs.keySet()) { + String jobId = ((List)key).get(0).toString(); + LOG.info("Attempting to remove Job: {}", jobId); + view.removeJob(jobId); + } + assertTrue(view.getAllJobs().isEmpty()); + } + + @Test + public void testRemvoeJobInRange() throws Exception { + JobSchedulerViewMBean view = getJobSchedulerMBean(); + assertNotNull(view); + assertTrue(view.getAllJobs().isEmpty()); + scheduleMessage(60000, -1, -1); + assertFalse(view.getAllJobs().isEmpty()); + String now = JobSupport.getDateTime(System.currentTimeMillis()); + String later = JobSupport.getDateTime(System.currentTimeMillis() + 120 * 1000); + view.removeAllJobs(now, later); + assertTrue(view.getAllJobs().isEmpty()); + } + + @Test + public void testGetNextScheduledJob() throws Exception { + JobSchedulerViewMBean view = getJobSchedulerMBean(); + assertNotNull(view); + assertTrue(view.getAllJobs().isEmpty()); + scheduleMessage(60000, -1, -1); + assertFalse(view.getAllJobs().isEmpty()); + long before = System.currentTimeMillis() + 57 * 1000; + long toLate = System.currentTimeMillis() + 63 * 1000; + String next = view.getNextScheduleTime(); + long nextTime = JobSupport.getDataTime(next); + LOG.info("Next Scheduled Time: {} should be after: {}", next, JobSupport.getDateTime(before)); + assertTrue(nextTime > before); + assertTrue(nextTime < toLate); + } + + @Test + public void testGetExecutionCount() throws Exception { + final JobSchedulerViewMBean view = getJobSchedulerMBean(); + assertNotNull(view); + assertTrue(view.getAllJobs().isEmpty()); + scheduleMessage(10000, 1000, 10); + assertFalse(view.getAllJobs().isEmpty()); + TabularData jobs = view.getAllJobs(); + assertEquals(1, jobs.size()); + String jobId = null; + for (Object key : jobs.keySet()) { + jobId = ((List)key).get(0).toString(); + } + + final String fixedJobId = jobId; + LOG.info("Attempting to get execution count for Job: {}", jobId); + assertEquals(0, view.getExecutionCount(jobId)); + + assertTrue("Should execute again", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return view.getExecutionCount(fixedJobId) > 0; + } + })); + } + + @Override + protected boolean isUseJmx() { + return true; + } + + protected void scheduleMessage(int time, int period, int repeat) throws Exception { + Connection connection = createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("test msg"); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, period); + message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, repeat); + producer.send(message); + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerManagementTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerManagementTest.java new file mode 100644 index 0000000000..c82f8ef1b4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerManagementTest.java @@ -0,0 +1,409 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.util.IdGenerator; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JobSchedulerManagementTest extends JobSchedulerTestSupport { + + private static final transient Logger LOG = LoggerFactory.getLogger(JobSchedulerManagementTest.class); + + @Test + public void testRemoveAllScheduled() throws Exception { + final int COUNT = 5; + Connection connection = createConnection(); + + // Setup the scheduled Message + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(6), COUNT); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the Browse Destination and the Reply To location + Destination management = session.createTopic(ScheduledMessage.AMQ_SCHEDULER_MANAGEMENT_DESTINATION); + + // Create the eventual Consumer to receive the scheduled message + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + connection.start(); + + // Send the remove request + MessageProducer producer = session.createProducer(management); + Message request = session.createMessage(); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_REMOVEALL); + producer.send(request); + + // Now wait and see if any get delivered, none should. + latch.await(10, TimeUnit.SECONDS); + assertEquals(latch.getCount(), COUNT); + } + + @Test + public void testRemoveAllScheduledAtTime() throws Exception { + final int COUNT = 3; + Connection connection = createConnection(); + + // Setup the scheduled Message + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(6)); + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(15)); + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(20)); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the Browse Destination and the Reply To location + Destination management = session.createTopic(ScheduledMessage.AMQ_SCHEDULER_MANAGEMENT_DESTINATION); + Destination browseDest = session.createTemporaryQueue(); + + // Create the eventual Consumer to receive the scheduled message + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + // Create the "Browser" + MessageConsumer browser = session.createConsumer(browseDest); + final CountDownLatch browsedLatch = new CountDownLatch(COUNT); + browser.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + browsedLatch.countDown(); + LOG.debug("Scheduled Message Browser got Message: " + message); + } + }); + + connection.start(); + + long start = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(10); + long end = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30); + + // Send the remove request + MessageProducer producer = session.createProducer(management); + Message request = session.createMessage(); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_REMOVEALL); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION_START_TIME, Long.toString(start)); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION_END_TIME, Long.toString(end)); + producer.send(request); + + // Send the browse request + request = session.createMessage(); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_BROWSE); + request.setJMSReplyTo(browseDest); + producer.send(request); + + // now see if we got back only the one remaining message. + latch.await(10, TimeUnit.SECONDS); + assertEquals(2, browsedLatch.getCount()); + + // Now wait and see if any get delivered, none should. + latch.await(10, TimeUnit.SECONDS); + assertEquals(2, latch.getCount()); + } + + @Test + public void testBrowseAllScheduled() throws Exception { + final int COUNT = 10; + Connection connection = createConnection(); + + // Setup the scheduled Message + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(9), COUNT); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the Browse Destination and the Reply To location + Destination requestBrowse = session.createTopic(ScheduledMessage.AMQ_SCHEDULER_MANAGEMENT_DESTINATION); + Destination browseDest = session.createTemporaryQueue(); + + // Create the eventual Consumer to receive the scheduled message + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + // Create the "Browser" + MessageConsumer browser = session.createConsumer(browseDest); + final CountDownLatch browsedLatch = new CountDownLatch(COUNT); + browser.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + browsedLatch.countDown(); + LOG.debug("Scheduled Message Browser got Message: " + message); + } + }); + + connection.start(); + + // Send the browse request + MessageProducer producer = session.createProducer(requestBrowse); + Message request = session.createMessage(); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_BROWSE); + request.setJMSReplyTo(browseDest); + producer.send(request); + + // make sure the message isn't delivered early because we browsed it + Thread.sleep(2000); + assertEquals(latch.getCount(), COUNT); + + // now see if we got all the scheduled messages on the browse + // destination. + latch.await(10, TimeUnit.SECONDS); + assertEquals(browsedLatch.getCount(), 0); + + // now check that they all got delivered + latch.await(10, TimeUnit.SECONDS); + assertEquals(latch.getCount(), 0); + } + + @Test + public void testBrowseWindowlScheduled() throws Exception { + final int COUNT = 10; + Connection connection = createConnection(); + + // Setup the scheduled Message + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(5)); + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(10), COUNT); + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(20)); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the Browse Destination and the Reply To location + Destination requestBrowse = session.createTopic(ScheduledMessage.AMQ_SCHEDULER_MANAGEMENT_DESTINATION); + Destination browseDest = session.createTemporaryQueue(); + + // Create the eventual Consumer to receive the scheduled message + MessageConsumer consumer = session.createConsumer(destination); + + final CountDownLatch latch = new CountDownLatch(COUNT + 2); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + // Create the "Browser" + MessageConsumer browser = session.createConsumer(browseDest); + final CountDownLatch browsedLatch = new CountDownLatch(COUNT); + browser.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + browsedLatch.countDown(); + LOG.debug("Scheduled Message Browser got Message: " + message); + } + }); + + connection.start(); + + long start = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(6); + long end = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(15); + + // Send the browse request + MessageProducer producer = session.createProducer(requestBrowse); + Message request = session.createMessage(); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_BROWSE); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION_START_TIME, Long.toString(start)); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION_END_TIME, Long.toString(end)); + request.setJMSReplyTo(browseDest); + producer.send(request); + + // make sure the message isn't delivered early because we browsed it + Thread.sleep(2000); + assertEquals(COUNT + 2, latch.getCount()); + + // now see if we got all the scheduled messages on the browse + // destination. + latch.await(15, TimeUnit.SECONDS); + assertEquals(0, browsedLatch.getCount()); + + // now see if we got all the scheduled messages on the browse + // destination. + latch.await(20, TimeUnit.SECONDS); + assertEquals(0, latch.getCount()); + } + + @Test + public void testRemoveScheduled() throws Exception { + final int COUNT = 10; + Connection connection = createConnection(); + + // Setup the scheduled Message + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(9), COUNT); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the Browse Destination and the Reply To location + Destination management = session.createTopic(ScheduledMessage.AMQ_SCHEDULER_MANAGEMENT_DESTINATION); + Destination browseDest = session.createTemporaryQueue(); + + // Create the eventual Consumer to receive the scheduled message + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(management); + + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + // Create the "Browser" + Session browseSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer browser = browseSession.createConsumer(browseDest); + + connection.start(); + + // Send the browse request + Message request = session.createMessage(); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_BROWSE); + request.setJMSReplyTo(browseDest); + producer.send(request); + + // Browse all the Scheduled Messages. + for (int i = 0; i < COUNT; ++i) { + Message message = browser.receive(2000); + assertNotNull(message); + + try { + Message remove = session.createMessage(); + remove.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_REMOVE); + remove.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_ID, message.getStringProperty(ScheduledMessage.AMQ_SCHEDULED_ID)); + producer.send(remove); + } catch (Exception e) { + } + } + + // now check that they all got removed and are not delivered. + latch.await(11, TimeUnit.SECONDS); + assertEquals(COUNT, latch.getCount()); + } + + @Test + public void testRemoveNotScheduled() throws Exception { + Connection connection = createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the Browse Destination and the Reply To location + Destination management = session.createTopic(ScheduledMessage.AMQ_SCHEDULER_MANAGEMENT_DESTINATION); + + MessageProducer producer = session.createProducer(management); + + try { + + // Send the remove request + Message remove = session.createMessage(); + remove.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_REMOVEALL); + remove.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_ID, new IdGenerator().generateId()); + producer.send(remove); + } catch (Exception e) { + fail("Caught unexpected exception during remove of unscheduled message."); + } + } + + @Test + public void testBrowseWithSelector() throws Exception { + Connection connection = createConnection(); + + // Setup the scheduled Message + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(9)); + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(10)); + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(5)); + scheduleMessage(connection, TimeUnit.SECONDS.toMillis(45)); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the Browse Destination and the Reply To location + Destination requestBrowse = session.createTopic(ScheduledMessage.AMQ_SCHEDULER_MANAGEMENT_DESTINATION); + Destination browseDest = session.createTemporaryTopic(); + + // Create the "Browser" + MessageConsumer browser = session.createConsumer(browseDest, ScheduledMessage.AMQ_SCHEDULED_DELAY + " = 45000"); + + connection.start(); + + // Send the browse request + MessageProducer producer = session.createProducer(requestBrowse); + Message request = session.createMessage(); + request.setStringProperty(ScheduledMessage.AMQ_SCHEDULER_ACTION, ScheduledMessage.AMQ_SCHEDULER_ACTION_BROWSE); + request.setJMSReplyTo(browseDest); + producer.send(request); + + // Now try and receive the one we selected + Message message = browser.receive(5000); + assertNotNull(message); + assertEquals(45000, message.getLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY)); + + // Now check if there are anymore, there shouldn't be + message = browser.receive(5000); + assertNull(message); + } + + protected void scheduleMessage(Connection connection, long delay) throws Exception { + scheduleMessage(connection, delay, 1); + } + + protected void scheduleMessage(Connection connection, long delay, int count) throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("test msg"); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay); + + for (int i = 0; i < count; ++i) { + producer.send(message); + } + + producer.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerStoreCheckpointTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerStoreCheckpointTest.java new file mode 100644 index 0000000000..c013a4c5f0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerStoreCheckpointTest.java @@ -0,0 +1,125 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.activemq.store.kahadb.scheduler.JobSchedulerStoreImpl; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JobSchedulerStoreCheckpointTest { + + static final Logger LOG = LoggerFactory.getLogger(JobSchedulerStoreCheckpointTest.class); + + private JobSchedulerStoreImpl store; + private JobScheduler scheduler; + private ByteSequence payload; + + @Before + public void setUp() throws Exception { + File directory = new File("target/test/ScheduledJobsDB"); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + startStore(directory); + + byte[] data = new byte[8192]; + for (int i = 0; i < data.length; ++i) { + data[i] = (byte) (i % 256); + } + + payload = new ByteSequence(data); + } + + protected void startStore(File directory) throws Exception { + store = new JobSchedulerStoreImpl(); + store.setDirectory(directory); + store.setCheckpointInterval(5000); + store.setCleanupInterval(10000); + store.setJournalMaxFileLength(10 * 1024); + store.start(); + scheduler = store.getJobScheduler("test"); + scheduler.startDispatching(); + } + + private int getNumJournalFiles() throws IOException { + return store.getJournal().getFileMap().size(); + } + + @After + public void tearDown() throws Exception { + scheduler.stopDispatching(); + store.stop(); + } + + @Test + public void test() throws Exception { + final int COUNT = 10; + final CountDownLatch latch = new CountDownLatch(COUNT); + scheduler.addListener(new JobListener() { + @Override + public void scheduledJob(String id, ByteSequence job) { + latch.countDown(); + } + }); + + long time = TimeUnit.SECONDS.toMillis(30); + for (int i = 0; i < COUNT; i++) { + scheduler.schedule("id" + i, payload, "", time, 0, 0); + } + + int size = scheduler.getAllJobs().size(); + assertEquals(size, COUNT); + + LOG.info("Number of journal log files: {}", getNumJournalFiles()); + // need a little slack so go over 60 seconds + assertTrue(latch.await(70, TimeUnit.SECONDS)); + assertEquals(0, latch.getCount()); + + for (int i = 0; i < COUNT; i++) { + scheduler.schedule("id" + i, payload, "", time, 0, 0); + } + + LOG.info("Number of journal log files: {}", getNumJournalFiles()); + // need a little slack so go over 60 seconds + assertTrue(latch.await(70, TimeUnit.SECONDS)); + assertEquals(0, latch.getCount()); + + assertTrue("Should be only one log left: " + getNumJournalFiles(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return getNumJournalFiles() == 1; + } + }, TimeUnit.MINUTES.toMillis(2))); + + LOG.info("Number of journal log files: {}", getNumJournalFiles()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerStoreTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerStoreTest.java new file mode 100644 index 0000000000..df1e7ff838 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerStoreTest.java @@ -0,0 +1,77 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq.store.kahadb.scheduler.JobSchedulerStoreImpl; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.util.IOHelper; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JobSchedulerStoreTest { + + private static final Logger LOG = LoggerFactory.getLogger(JobSchedulerStoreTest.class); + + @Test(timeout = 120 * 1000) + public void testRestart() throws Exception { + JobSchedulerStore store = new JobSchedulerStoreImpl(); + File directory = new File("target/test/ScheduledDB"); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store.setDirectory(directory); + final int NUMBER = 1000; + store.start(); + List list = new ArrayList(); + for (int i = 0; i < NUMBER; i++) { + ByteSequence buff = new ByteSequence(new String("testjob" + i).getBytes()); + list.add(buff); + } + + JobScheduler js = store.getJobScheduler("test"); + js.startDispatching(); + int count = 0; + long startTime = 10 * 60 * 1000; + long period = startTime; + for (ByteSequence job : list) { + js.schedule("id:" + (count++), job, "", startTime, period, -1); + } + + List test = js.getAllJobs(); + LOG.debug("Found {} jobs in the store before restart", test.size()); + assertEquals(list.size(), test.size()); + store.stop(); + + store.start(); + js = store.getJobScheduler("test"); + test = js.getAllJobs(); + LOG.debug("Found {} jobs in the store after restart", test.size()); + assertEquals(list.size(), test.size()); + + for (int i = 0; i < list.size(); i++) { + String orig = new String(list.get(i).getData()); + String payload = new String(test.get(i).getPayload()); + assertEquals(orig, payload); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTest.java new file mode 100644 index 0000000000..b84a782c4b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTest.java @@ -0,0 +1,297 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.Calendar; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.activemq.store.kahadb.scheduler.JobSchedulerStoreImpl; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JobSchedulerTest { + + private static final Logger LOG = LoggerFactory.getLogger(JobSchedulerTest.class); + + private JobSchedulerStore store; + private JobScheduler scheduler; + + @Test + public void testAddLongStringByteSequence() throws Exception { + final int COUNT = 10; + final CountDownLatch latch = new CountDownLatch(COUNT); + scheduler.addListener(new JobListener() { + @Override + public void scheduledJob(String id, ByteSequence job) { + latch.countDown(); + } + + }); + for (int i = 0; i < COUNT; i++) { + String test = new String("test" + i); + scheduler.schedule("id" + i, new ByteSequence(test.getBytes()), 1000); + } + latch.await(5, TimeUnit.SECONDS); + assertEquals(0, latch.getCount()); + } + + @Test + public void testAddCronAndByteSequence() throws Exception { + + final CountDownLatch latch = new CountDownLatch(1); + scheduler.addListener(new JobListener() { + @Override + public void scheduledJob(String id, ByteSequence job) { + latch.countDown(); + } + }); + + Calendar current = Calendar.getInstance(); + current.add(Calendar.MINUTE, 1); + int minutes = current.get(Calendar.MINUTE); + int hour = current.get(Calendar.HOUR_OF_DAY); + int day = current.get(Calendar.DAY_OF_WEEK) - 1; + + String cronTab = String.format("%d %d * * %d", minutes, hour, day); + + String str = new String("test1"); + scheduler.schedule("id:1", new ByteSequence(str.getBytes()), cronTab, 0, 0, 0); + + // need a little slack so go over 60 seconds + assertTrue(latch.await(70, TimeUnit.SECONDS)); + assertEquals(0, latch.getCount()); + } + + @Test + public void testAddLongLongIntStringByteSequence() throws Exception { + final int COUNT = 10; + final CountDownLatch latch = new CountDownLatch(COUNT); + scheduler.addListener(new JobListener() { + @Override + public void scheduledJob(String id, ByteSequence job) { + latch.countDown(); + } + }); + long time = 2000; + for (int i = 0; i < COUNT; i++) { + String test = new String("test" + i); + scheduler.schedule("id" + i, new ByteSequence(test.getBytes()), "", time, 10, -1); + } + assertTrue(latch.getCount() == COUNT); + latch.await(3000, TimeUnit.SECONDS); + assertTrue(latch.getCount() == 0); + } + + @Test + public void testAddStopThenDeliver() throws Exception { + final int COUNT = 10; + final CountDownLatch latch = new CountDownLatch(COUNT); + long time = 2000; + for (int i = 0; i < COUNT; i++) { + String test = new String("test" + i); + scheduler.schedule("id" + i, new ByteSequence(test.getBytes()), "", time, 1000, -1); + } + File directory = store.getDirectory(); + tearDown(); + startStore(directory); + scheduler.addListener(new JobListener() { + @Override + public void scheduledJob(String id, ByteSequence job) { + latch.countDown(); + } + }); + assertTrue(latch.getCount() == COUNT); + latch.await(3000, TimeUnit.SECONDS); + assertTrue(latch.getCount() == 0); + } + + @Test + public void testRemoveLong() throws Exception { + final int COUNT = 10; + + long time = 60000; + for (int i = 0; i < COUNT; i++) { + String str = new String("test" + i); + scheduler.schedule("id" + i, new ByteSequence(str.getBytes()), "", time, 1000, -1); + } + + int size = scheduler.getAllJobs().size(); + assertEquals(size, COUNT); + + long removeTime = scheduler.getNextScheduleTime(); + scheduler.remove(removeTime); + + // If all jobs are not started within the same second we need to call remove again + if (size != 0) { + removeTime = scheduler.getNextScheduleTime(); + scheduler.remove(removeTime); + } + + size = scheduler.getAllJobs().size(); + assertEquals(0, size); + } + + @Test + public void testRemoveString() throws Exception { + final int COUNT = 10; + final String test = "TESTREMOVE"; + long time = 20000; + + for (int i = 0; i < COUNT; i++) { + String str = new String("test" + i); + scheduler.schedule("id" + i, new ByteSequence(str.getBytes()), "", time, 1000, -1); + if (i == COUNT / 2) { + scheduler.schedule(test, new ByteSequence(test.getBytes()), "", time, 1000, -1); + } + } + + int size = scheduler.getAllJobs().size(); + assertEquals(size, COUNT + 1); + scheduler.remove(test); + size = scheduler.getAllJobs().size(); + assertEquals(size, COUNT); + } + + @Test + public void testGetExecutionCount() throws Exception { + final String jobId = "Job-1"; + long time = 10000; + final CountDownLatch done = new CountDownLatch(10); + + String str = new String("test"); + scheduler.schedule(jobId, new ByteSequence(str.getBytes()), "", time, 1000, 10); + + int size = scheduler.getAllJobs().size(); + assertEquals(size, 1); + + scheduler.addListener(new JobListener() { + @Override + public void scheduledJob(String id, ByteSequence job) { + LOG.info("Job exectued: {}", 11 - done.getCount()); + done.countDown(); + } + }); + + List jobs = scheduler.getNextScheduleJobs(); + assertEquals(1, jobs.size()); + Job job = jobs.get(0); + assertEquals(jobId, job.getJobId()); + assertEquals(0, job.getExecutionCount()); + assertTrue("Should have fired ten times.", done.await(60, TimeUnit.SECONDS)); + // The job is not updated on the last firing as it is removed from the store following + // it's last execution so the count will always be one less than the max firings. + assertTrue(job.getExecutionCount() >= 9); + } + + @Test + public void testgetAllJobs() throws Exception { + final int COUNT = 10; + final String ID = "id:"; + long time = 20000; + + for (int i = 0; i < COUNT; i++) { + String str = new String("test" + i); + scheduler.schedule(ID + i, new ByteSequence(str.getBytes()), "", time, 10 + i, -1); + } + + List list = scheduler.getAllJobs(); + + assertEquals(list.size(), COUNT); + int count = 0; + for (Job job : list) { + assertEquals(job.getJobId(), ID + count); + count++; + } + } + + @Test + public void testgetAllJobsInRange() throws Exception { + final int COUNT = 10; + final String ID = "id:"; + long start = 10000; + + for (int i = 0; i < COUNT; i++) { + String str = new String("test" + i); + scheduler.schedule(ID + i, new ByteSequence(str.getBytes()), "", start + (i * 1000), 10000 + i, 0); + } + + start = System.currentTimeMillis(); + long finish = start + 12000 + (COUNT * 1000); + List list = scheduler.getAllJobs(start, finish); + + assertEquals(COUNT, list.size()); + int count = 0; + for (Job job : list) { + assertEquals(job.getJobId(), ID + count); + count++; + } + } + + @Test + public void testRemoveAllJobsInRange() throws Exception { + final int COUNT = 10; + final String ID = "id:"; + long start = 10000; + + for (int i = 0; i < COUNT; i++) { + String str = new String("test" + i); + scheduler.schedule(ID + i, new ByteSequence(str.getBytes()), "", start + (i * 1000), 10000 + i, 0); + } + start = System.currentTimeMillis(); + long finish = start + 12000 + (COUNT * 1000); + scheduler.removeAllJobs(start, finish); + + assertTrue(scheduler.getAllJobs().isEmpty()); + } + + @Before + public void setUp() throws Exception { + File directory = new File("target/test/ScheduledJobsDB"); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + startStore(directory); + } + + protected JobSchedulerStore createJobSchedulerStore() throws Exception { + return new JobSchedulerStoreImpl(); + } + + protected void startStore(File directory) throws Exception { + store = createJobSchedulerStore(); + store.setDirectory(directory); + store.start(); + scheduler = store.getJobScheduler("test"); + scheduler.startDispatching(); + } + + @After + public void tearDown() throws Exception { + scheduler.stopDispatching(); + store.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTestSupport.java new file mode 100644 index 0000000000..5bf8d8c45a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTestSupport.java @@ -0,0 +1,116 @@ +/** + * 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.broker.scheduler; + +import java.io.File; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Queue; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.JobSchedulerViewMBean; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestName; + +/** + * Base class for tests of the Broker's JobSchedulerStore. + */ +public class JobSchedulerTestSupport { + + @Rule public TestName name = new TestName(); + + protected String connectionUri; + protected BrokerService broker; + protected JobScheduler jobScheduler; + protected Queue destination; + + @Before + public void setUp() throws Exception { + connectionUri = "vm://localhost"; + destination = new ActiveMQQueue(name.getMethodName()); + + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + + jobScheduler = broker.getJobSchedulerStore().getJobScheduler("JMS"); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + protected Connection createConnection() throws Exception { + return createConnectionFactory().createConnection(); + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(connectionUri); + } + + protected BrokerService createBroker() throws Exception { + return createBroker(true); + } + + protected boolean isUseJmx() { + return false; + } + + protected boolean isPersistent() { + return true; + } + + protected JobSchedulerViewMBean getJobSchedulerMBean() throws Exception { + ObjectName objectName = broker.getAdminView().getJMSJobScheduler(); + JobSchedulerViewMBean scheduler = null; + if (objectName != null) { + scheduler = (JobSchedulerViewMBean) broker.getManagementContext() + .newProxyInstance(objectName, JobSchedulerViewMBean.class, true); + } + + return scheduler; + } + + protected BrokerService createBroker(boolean delete) throws Exception { + File schedulerDirectory = new File("target/scheduler"); + if (delete) { + IOHelper.mkdirs(schedulerDirectory); + IOHelper.deleteChildren(schedulerDirectory); + } + + BrokerService answer = new BrokerService(); + answer.setPersistent(isPersistent()); + answer.setDeleteAllMessagesOnStartup(true); + answer.setDataDirectory("target"); + answer.setSchedulerDirectoryFile(schedulerDirectory); + answer.setSchedulerSupport(true); + answer.setUseJmx(isUseJmx()); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTxTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTxTest.java new file mode 100644 index 0000000000..996cc55b1a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JobSchedulerTxTest.java @@ -0,0 +1,107 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ScheduledMessage; +import org.junit.Test; + +public class JobSchedulerTxTest extends JobSchedulerTestSupport { + + @Test + public void testTxSendWithRollback() throws Exception { + final int COUNT = 10; + Connection connection = createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + connection.start(); + long time = 5000; + Session producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = producerSession.createProducer(destination); + + for (int i = 0; i < COUNT; ++i) { + TextMessage message = session.createTextMessage("test msg"); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + producer.send(message); + } + producer.close(); + producerSession.rollback(); + + // make sure the message isn't delivered early + Thread.sleep(2000); + assertEquals(COUNT, latch.getCount()); + latch.await(5, TimeUnit.SECONDS); + assertEquals(COUNT, latch.getCount()); + } + + @Test + public void testTxSendWithCommit() throws Exception { + final int COUNT = 10; + Connection connection = createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + final CountDownLatch latch = new CountDownLatch(COUNT); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + } + }); + + connection.start(); + long time = 5000; + Session producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = producerSession.createProducer(destination); + + for (int i = 0; i < COUNT; ++i) { + TextMessage message = session.createTextMessage("test msg"); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + producer.send(message); + } + producer.close(); + producerSession.commit(); + + // make sure the message isn't delivered early + Thread.sleep(2000); + assertEquals(COUNT, latch.getCount()); + latch.await(5, TimeUnit.SECONDS); + assertEquals(0, latch.getCount()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/KahaDBSchedulerIndexRebuildTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/KahaDBSchedulerIndexRebuildTest.java new file mode 100644 index 0000000000..03e5c84c81 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/KahaDBSchedulerIndexRebuildTest.java @@ -0,0 +1,195 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.security.ProtectionDomain; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.scheduler.JobSchedulerStoreImpl; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KahaDBSchedulerIndexRebuildTest { + + static final Logger LOG = LoggerFactory.getLogger(KahaDBSchedulerIndexRebuildTest.class); + + private BrokerService broker = null; + private final int NUM_JOBS = 50; + + static String basedir; + static { + try { + ProtectionDomain protectionDomain = SchedulerDBVersionTest.class.getProtectionDomain(); + basedir = new File(new File(protectionDomain.getCodeSource().getLocation().getPath()), "../.").getCanonicalPath(); + } catch (IOException e) { + basedir = "."; + } + } + + private final File schedulerStoreDir = new File(basedir, "activemq-data/store/scheduler"); + private final File storeDir = new File(basedir, "activemq-data/store/"); + + @Before + public void setUp() throws Exception { + LOG.info("Test Dir = {}", schedulerStoreDir); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + @Test + public void testIndexRebuilds() throws Exception { + IOHelper.deleteFile(schedulerStoreDir); + + JobSchedulerStoreImpl schedulerStore = createScheduler(); + broker = createBroker(schedulerStore); + broker.start(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.start(); + for (int i = 0; i < NUM_JOBS; ++i) { + scheduleRepeating(connection); + } + connection.close(); + + JobScheduler scheduler = schedulerStore.getJobScheduler("JMS"); + assertNotNull(scheduler); + assertEquals(NUM_JOBS, scheduler.getAllJobs().size()); + + broker.stop(); + + IOHelper.delete(new File(schedulerStoreDir, "scheduleDB.data")); + + schedulerStore = createScheduler(); + broker = createBroker(schedulerStore); + broker.start(); + + scheduler = schedulerStore.getJobScheduler("JMS"); + assertNotNull(scheduler); + assertEquals(NUM_JOBS, scheduler.getAllJobs().size()); + } + + @Test + public void testIndexRebuildsAfterSomeJobsExpire() throws Exception { + IOHelper.deleteFile(schedulerStoreDir); + + JobSchedulerStoreImpl schedulerStore = createScheduler(); + broker = createBroker(schedulerStore); + broker.start(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.start(); + for (int i = 0; i < NUM_JOBS; ++i) { + scheduleRepeating(connection); + scheduleOneShot(connection); + } + connection.close(); + + JobScheduler scheduler = schedulerStore.getJobScheduler("JMS"); + assertNotNull(scheduler); + assertEquals(NUM_JOBS * 2, scheduler.getAllJobs().size()); + + final JobScheduler awaitingOneShotTimeout = scheduler; + assertTrue("One shot jobs should time out", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return awaitingOneShotTimeout.getAllJobs().size() == NUM_JOBS; + } + }, TimeUnit.MINUTES.toMillis(2))); + + broker.stop(); + + IOHelper.delete(new File(schedulerStoreDir, "scheduleDB.data")); + + schedulerStore = createScheduler(); + broker = createBroker(schedulerStore); + broker.start(); + + scheduler = schedulerStore.getJobScheduler("JMS"); + assertNotNull(scheduler); + assertEquals(NUM_JOBS, scheduler.getAllJobs().size()); + } + + private void scheduleRepeating(Connection connection) throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("test.queue"); + MessageProducer producer = session.createProducer(queue); + + TextMessage message = session.createTextMessage("test msg"); + long time = 360 * 1000; + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 500); + message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, -1); + producer.send(message); + producer.close(); + } + + private void scheduleOneShot(Connection connection) throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("test.queue"); + MessageProducer producer = session.createProducer(queue); + + TextMessage message = session.createTextMessage("test msg"); + long time = TimeUnit.SECONDS.toMillis(30); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, 0); + producer.send(message); + producer.close(); + } + + protected JobSchedulerStoreImpl createScheduler() { + JobSchedulerStoreImpl scheduler = new JobSchedulerStoreImpl(); + scheduler.setDirectory(schedulerStoreDir); + scheduler.setJournalMaxFileLength(10 * 1024); + return scheduler; + } + + protected BrokerService createBroker(JobSchedulerStoreImpl scheduler) throws Exception { + BrokerService answer = new BrokerService(); + answer.setJobSchedulerStore(scheduler); + answer.setPersistent(true); + answer.setDataDirectory(storeDir.getAbsolutePath()); + answer.setSchedulerSupport(true); + answer.setUseJmx(false); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/KahaDBSchedulerMissingJournalLogsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/KahaDBSchedulerMissingJournalLogsTest.java new file mode 100644 index 0000000000..30da10dfb7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/KahaDBSchedulerMissingJournalLogsTest.java @@ -0,0 +1,204 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.disk.journal.DataFile; +import org.apache.activemq.store.kahadb.scheduler.JobSchedulerStoreImpl; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + *Test that the store recovers even if some log files are missing. + */ +public class KahaDBSchedulerMissingJournalLogsTest { + + static final Logger LOG = LoggerFactory.getLogger(KahaDBSchedulerIndexRebuildTest.class); + + private BrokerService broker = null; + private JobSchedulerStoreImpl schedulerStore = null; + + private final int NUM_LOGS = 6; + + static String basedir; + static { + try { + ProtectionDomain protectionDomain = SchedulerDBVersionTest.class.getProtectionDomain(); + basedir = new File(new File(protectionDomain.getCodeSource().getLocation().getPath()), "../.").getCanonicalPath(); + } catch (IOException e) { + basedir = "."; + } + } + + private final File schedulerStoreDir = new File(basedir, "activemq-data/store/scheduler"); + private final File storeDir = new File(basedir, "activemq-data/store/"); + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + IOHelper.deleteFile(schedulerStoreDir); + LOG.info("Test Dir = {}", schedulerStoreDir); + + createBroker(); + broker.start(); + broker.waitUntilStarted(); + + schedulerStore = (JobSchedulerStoreImpl) broker.getJobSchedulerStore(); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test(timeout=120 * 1000) + public void testMissingLogsCausesBrokerToFail() throws Exception { + fillUpSomeLogFiles(); + + int jobCount = schedulerStore.getJobScheduler("JMS").getAllJobs().size(); + LOG.info("There are {} jobs in the store.", jobCount); + + List toDelete = new ArrayList(); + Map files = schedulerStore.getJournal().getFileMap(); + for (int i = files.size(); i > files.size() / 2; i--) { + toDelete.add(files.get(i).getFile()); + } + + broker.stop(); + broker.waitUntilStopped(); + + for (File file : toDelete) { + LOG.info("File to delete: {}", file); + IOHelper.delete(file); + } + + try { + createBroker(); + fail("Should not start when logs are missing."); + } catch (Exception e) { + } + } + + @Test(timeout=120 * 1000) + public void testRecoverWhenSomeLogsAreMissing() throws Exception { + fillUpSomeLogFiles(); + + int jobCount = schedulerStore.getJobScheduler("JMS").getAllJobs().size(); + LOG.info("There are {} jobs in the store.", jobCount); + + List toDelete = new ArrayList(); + Map files = schedulerStore.getJournal().getFileMap(); + for (int i = files.size() - 1; i > files.size() / 2; i--) { + toDelete.add(files.get(i).getFile()); + } + + broker.stop(); + broker.waitUntilStopped(); + + for (File file : toDelete) { + LOG.info("File to delete: {}", file); + IOHelper.delete(file); + } + + schedulerStore = createScheduler(); + schedulerStore.setIgnoreMissingJournalfiles(true); + + createBroker(schedulerStore); + broker.start(); + broker.waitUntilStarted(); + + int postRecoverJobCount = schedulerStore.getJobScheduler("JMS").getAllJobs().size(); + assertTrue(postRecoverJobCount > 0); + assertTrue(postRecoverJobCount < jobCount); + } + + private void fillUpSomeLogFiles() throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("test.queue"); + MessageProducer producer = session.createProducer(queue); + connection.start(); + while (true) { + scheduleRepeating(session, producer); + if (schedulerStore.getJournal().getFileMap().size() == NUM_LOGS) { + break; + } + } + connection.close(); + } + + private void scheduleRepeating(Session session, MessageProducer producer) throws Exception { + TextMessage message = session.createTextMessage("test msg"); + long time = 360 * 1000; + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 500); + message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, -1); + producer.send(message); + } + + protected JobSchedulerStoreImpl createScheduler() { + JobSchedulerStoreImpl scheduler = new JobSchedulerStoreImpl(); + scheduler.setDirectory(schedulerStoreDir); + scheduler.setJournalMaxFileLength(10 * 1024); + return scheduler; + } + + protected void createBroker() throws Exception { + createBroker(createScheduler()); + } + + protected void createBroker(JobSchedulerStoreImpl scheduler) throws Exception { + broker = new BrokerService(); + broker.setJobSchedulerStore(scheduler); + broker.setPersistent(true); + broker.setDataDirectory(storeDir.getAbsolutePath()); + broker.setSchedulerSupport(true); + broker.setUseJmx(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/LostScheduledMessagesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/LostScheduledMessagesTest.java new file mode 100644 index 0000000000..53588b5b69 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/LostScheduledMessagesTest.java @@ -0,0 +1,153 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.IOHelper; +import org.apache.log4j.BasicConfigurator; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class LostScheduledMessagesTest { + + private BrokerService broker; + + private static final File schedulerDirectory = new File("target/test/ScheduledDB"); + private static final File messageDirectory = new File("target/test/MessageDB"); + private static final String QUEUE_NAME = "test"; + + @Before + public void setup() throws Exception { + IOHelper.mkdirs(schedulerDirectory); + IOHelper.deleteChildren(schedulerDirectory); + + IOHelper.mkdirs(messageDirectory); + IOHelper.deleteChildren(messageDirectory); + } + + private void startBroker() throws Exception { + broker = new BrokerService(); + broker.setSchedulerSupport(true); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(false); + broker.setDataDirectory("target"); + broker.setSchedulerDirectoryFile(schedulerDirectory); + broker.setDataDirectoryFile(messageDirectory); + broker.setUseJmx(false); + broker.addConnector("vm://localhost"); + broker.start(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + BasicConfigurator.resetConfiguration(); + } + + @Test + public void MessagePassedNotUsingScheduling() throws Exception { + doTest(false); + } + + @Test + public void MessageLostWhenUsingScheduling() throws Exception { + doTest(true); + } + + private void doTest(boolean useScheduling) throws Exception { + + int DELIVERY_DELAY_MS = 5000; + + startBroker(); + + long startTime = System.currentTimeMillis(); + + // Send a message scheduled for delivery in 5 seconds + ConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME)); + Message message = session.createTextMessage("test"); + if (useScheduling) { + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, DELIVERY_DELAY_MS); + } + producer.send(message); + + session.close(); + connection.close(); + + broker.getServices(); + + // shut down broker + broker.stop(); + broker.waitUntilStopped(); + + // Make sure that broker have stopped within delivery delay + long shutdownTime = System.currentTimeMillis(); + assertTrue("Failed to shut down broker in expected time. Test results inconclusive", shutdownTime - startTime < DELIVERY_DELAY_MS); + + // make sure that delivery falls into down time window + TimeUnit.MILLISECONDS.sleep(DELIVERY_DELAY_MS); + + // Start new broker instance + startBroker(); + + final AtomicLong receiveCounter = new AtomicLong(); + + cf = new ActiveMQConnectionFactory("vm://localhost"); + connection = cf.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + receiveCounter.incrementAndGet(); + } + }); + + // Wait for a while to let MQ process the message + TimeUnit.MILLISECONDS.sleep(DELIVERY_DELAY_MS * 2); + + session.close(); + connection.close(); + + assertEquals(1, receiveCounter.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/SchedulerDBVersionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/SchedulerDBVersionTest.java new file mode 100644 index 0000000000..721f41702d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/SchedulerDBVersionTest.java @@ -0,0 +1,164 @@ +/** + * 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.broker.scheduler; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.security.ProtectionDomain; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.scheduler.JobSchedulerStoreImpl; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SchedulerDBVersionTest { + static String basedir; + static { + try { + ProtectionDomain protectionDomain = SchedulerDBVersionTest.class.getProtectionDomain(); + basedir = new File(new File(protectionDomain.getCodeSource().getLocation().getPath()), "../..").getCanonicalPath(); + } catch (IOException e) { + basedir = "."; + } + } + + static final Logger LOG = LoggerFactory.getLogger(SchedulerDBVersionTest.class); + final static File VERSION_LEGACY_JMS = + new File(basedir + "/src/test/resources/org/apache/activemq/store/schedulerDB/legacy"); + + BrokerService broker = null; + + protected BrokerService createBroker(JobSchedulerStoreImpl scheduler) throws Exception { + BrokerService answer = new BrokerService(); + answer.setJobSchedulerStore(scheduler); + answer.setPersistent(true); + answer.setDataDirectory("target"); + answer.setSchedulerSupport(true); + answer.setUseJmx(false); + return answer; + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + @Ignore("Used only when a new version of the store needs to archive it's test data.") + @Test + public void testCreateStore() throws Exception { + JobSchedulerStoreImpl scheduler = new JobSchedulerStoreImpl(); + File dir = new File("src/test/resources/org/apache/activemq/store/schedulerDB/legacy"); + IOHelper.deleteFile(dir); + scheduler.setDirectory(dir); + scheduler.setJournalMaxFileLength(1024 * 1024); + broker = createBroker(scheduler); + broker.start(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.start(); + scheduleRepeating(connection); + connection.close(); + broker.stop(); + } + + private void scheduleRepeating(Connection connection) throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("test.queue"); + MessageProducer producer = session.createProducer(queue); + + TextMessage message = session.createTextMessage("test msg"); + long time = 1000; + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 500); + message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, -1); + producer.send(message); + producer.close(); + } + + @Test + public void testLegacyStoreConversion() throws Exception { + doTestScheduleRepeated(VERSION_LEGACY_JMS); + } + + public void doTestScheduleRepeated(File existingStore) throws Exception { + File testDir = new File("target/activemq-data/store/scheduler/versionDB"); + IOHelper.deleteFile(testDir); + IOHelper.copyFile(existingStore, testDir); + + final int NUMBER = 10; + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + + for (int i = 0; i < 3; ++i) { + JobSchedulerStoreImpl scheduler = new JobSchedulerStoreImpl(); + scheduler.setDirectory(testDir); + scheduler.setJournalMaxFileLength(1024 * 1024); + BrokerService broker = createBroker(scheduler); + broker.start(); + broker.waitUntilStarted(); + + final AtomicInteger count = new AtomicInteger(); + Connection connection = cf.createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("test.queue"); + + MessageConsumer consumer = session.createConsumer(queue); + + final CountDownLatch latch = new CountDownLatch(NUMBER); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + LOG.info("Received scheduled message: {}", message); + latch.countDown(); + count.incrementAndGet(); + } + }); + + connection.start(); + assertEquals(latch.getCount(), NUMBER); + latch.await(30, TimeUnit.SECONDS); + + connection.close(); + broker.stop(); + broker.waitUntilStopped(); + + assertEquals(0, latch.getCount()); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemeoryJmsSchedulerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemeoryJmsSchedulerTest.java new file mode 100644 index 0000000000..5144203e72 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemeoryJmsSchedulerTest.java @@ -0,0 +1,40 @@ +/** + * 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.broker.scheduler.memory; + +import org.apache.activemq.broker.scheduler.JmsSchedulerTest; + +/** + * Test for the In-Memory Scheduler variant. + */ +public class InMemeoryJmsSchedulerTest extends JmsSchedulerTest { + + @Override + protected boolean isPersistent() { + return false; + } + + @Override + public void testScheduleRestart() throws Exception { + // No persistence so scheduled jobs don't survive restart. + } + + @Override + public void testJobSchedulerStoreUsage() throws Exception { + // No store usage numbers for in-memory store. + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJmsCronSchedulerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJmsCronSchedulerTest.java new file mode 100644 index 0000000000..a3b7d04688 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJmsCronSchedulerTest.java @@ -0,0 +1,30 @@ +/** + * 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.broker.scheduler.memory; + +import org.apache.activemq.broker.scheduler.JmsCronSchedulerTest; + +/** + * In memory version of the cron scheduler test. + */ +public class InMemoryJmsCronSchedulerTest extends JmsCronSchedulerTest { + + @Override + protected boolean isPersistent() { + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerJmxManagementTests.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerJmxManagementTests.java new file mode 100644 index 0000000000..46f55404af --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerJmxManagementTests.java @@ -0,0 +1,30 @@ +/** + * 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.broker.scheduler.memory; + +import org.apache.activemq.broker.scheduler.JobSchedulerJmxManagementTests; + +/** + * Test for the In-Memory scheduler's JMX management features. + */ +public class InMemoryJobSchedulerJmxManagementTests extends JobSchedulerJmxManagementTests { + + @Override + protected boolean isPersistent() { + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerManagementTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerManagementTest.java new file mode 100644 index 0000000000..e65d819e5c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerManagementTest.java @@ -0,0 +1,30 @@ +/** + * 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.broker.scheduler.memory; + +import org.apache.activemq.broker.scheduler.JobSchedulerManagementTest; + +/** + * Tests management of in memory scheduler via JMS client. + */ +public class InMemoryJobSchedulerManagementTest extends JobSchedulerManagementTest { + + @Override + protected boolean isPersistent() { + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerStoreTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerStoreTest.java new file mode 100644 index 0000000000..ac90070d1f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerStoreTest.java @@ -0,0 +1,74 @@ +/** + * 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.broker.scheduler.memory; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq.broker.scheduler.Job; +import org.apache.activemq.broker.scheduler.JobScheduler; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.util.IOHelper; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class InMemoryJobSchedulerStoreTest { + + private static final Logger LOG = LoggerFactory.getLogger(InMemoryJobSchedulerStoreTest.class); + + @Test(timeout = 120 * 1000) + public void testRestart() throws Exception { + InMemoryJobSchedulerStore store = new InMemoryJobSchedulerStore(); + File directory = new File("target/test/ScheduledDB"); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store.setDirectory(directory); + final int NUMBER = 1000; + store.start(); + List list = new ArrayList(); + for (int i = 0; i < NUMBER; i++) { + ByteSequence buff = new ByteSequence(new String("testjob" + i).getBytes()); + list.add(buff); + } + + JobScheduler js = store.getJobScheduler("test"); + js.startDispatching(); + int count = 0; + long startTime = 10 * 60 * 1000; + long period = startTime; + for (ByteSequence job : list) { + js.schedule("id:" + (count++), job, "", startTime, period, -1); + } + + List test = js.getAllJobs(); + LOG.debug("Found {} jobs in the store before restart", test.size()); + assertEquals(list.size(), test.size()); + store.stop(); + store.start(); + js = store.getJobScheduler("test"); + test = js.getAllJobs(); + LOG.debug("Found {} jobs in the store after restart", test.size()); + assertEquals(0, test.size()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerTest.java new file mode 100644 index 0000000000..36771b0352 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerTest.java @@ -0,0 +1,36 @@ +/** + * 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.broker.scheduler.memory; + +import org.apache.activemq.broker.scheduler.JobSchedulerStore; +import org.apache.activemq.broker.scheduler.JobSchedulerTest; + +/** + * In-Memory store based variation of the JobSchedulerTest + */ +public class InMemoryJobSchedulerTest extends JobSchedulerTest { + + @Override + public void testAddStopThenDeliver() throws Exception { + // In Memory store that's stopped doesn't retain the jobs. + } + + @Override + protected JobSchedulerStore createJobSchedulerStore() throws Exception { + return new InMemoryJobSchedulerStore(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerTxTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerTxTest.java new file mode 100644 index 0000000000..fb87905881 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/memory/InMemoryJobSchedulerTxTest.java @@ -0,0 +1,30 @@ +/** + * 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.broker.scheduler.memory; + +import org.apache.activemq.broker.scheduler.JobSchedulerTxTest; + +/** + * In memory version of the TX test case + */ +public class InMemoryJobSchedulerTxTest extends JobSchedulerTxTest { + + @Override + protected boolean isPersistent() { + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/spring.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/spring.xml new file mode 100644 index 0000000000..7d37217f47 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/spring.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + tcp://localhost:61616 + tcp://localhost:61636 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + org.apache.activemq.spring.Test.spring.topic + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/DefaultStoreBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/DefaultStoreBrokerTest.java new file mode 100644 index 0000000000..1e9633af22 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/DefaultStoreBrokerTest.java @@ -0,0 +1,50 @@ +/** + * 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.broker.store; + +import java.net.URI; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTest; + +/** + * Once the wire format is completed we can test against real persistence storage. + * + * + */ +public class DefaultStoreBrokerTest extends BrokerTest { + + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://()/localhost?deleteAllMessagesOnStartup=true")); + } + + protected BrokerService createRestartedBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://()/localhost")); + } + + public static Test suite() { + return suite(DefaultStoreBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/DefaultStoreRecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/DefaultStoreRecoveryBrokerTest.java new file mode 100644 index 0000000000..e89ca04a24 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/DefaultStoreRecoveryBrokerTest.java @@ -0,0 +1,50 @@ +/** + * 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.broker.store; + +import java.net.URI; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.RecoveryBrokerTest; + +/** + * Used to verify that recovery works correctly against + * + * + */ +public class DefaultStoreRecoveryBrokerTest extends RecoveryBrokerTest { + + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://()/localhost?deleteAllMessagesOnStartup=true")); + } + + protected BrokerService createRestartedBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://()/localhost")); + } + + public static Test suite() { + return suite(DefaultStoreRecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/LoadTester.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/LoadTester.java new file mode 100644 index 0000000000..a6d78b4a60 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/LoadTester.java @@ -0,0 +1,110 @@ +/** + * 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.broker.store; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.jms.BytesMessage; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ProgressPrinter; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class LoadTester extends JmsTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(LoadTester.class); + + protected int messageSize = 1024 * 64; + protected int produceCount = 10000; + + @Override + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/broker/store/loadtester.xml")); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws URISyntaxException, IOException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getServer().getConnectURI()); + factory.setUseAsyncSend(true); + return factory; + } + + public void testQueueSendThenAddConsumer() throws Exception { + ProgressPrinter printer = new ProgressPrinter(produceCount, 20); + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + connection.setUseCompression(false); + connection.getPrefetchPolicy().setAll(10); + connection.start(); + Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + LOG.info("Sending " + produceCount + " messages that are " + (messageSize / 1024.0) + "k large, for a total of " + (produceCount * messageSize / (1024.0 * 1024.0)) + + " megs of data."); + // Send a message to the broker. + long start = System.currentTimeMillis(); + for (int i = 0; i < produceCount; i++) { + printer.increment(); + BytesMessage msg = session.createBytesMessage(); + msg.writeBytes(new byte[messageSize]); + producer.send(msg); + } + long end1 = System.currentTimeMillis(); + + LOG.info("Produced messages/sec: " + (produceCount * 1000.0 / (end1 - start))); + + printer = new ProgressPrinter(produceCount, 10); + start = System.currentTimeMillis(); + MessageConsumer consumer = session.createConsumer(destination); + for (int i = 0; i < produceCount; i++) { + printer.increment(); + assertNotNull("Getting message: " + i, consumer.receive(20000)); + } + end1 = System.currentTimeMillis(); + LOG.info("Consumed messages/sec: " + (produceCount * 1000.0 / (end1 - start))); + + } + + public static Test suite() { + return suite(LoadTester.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/RecoverExpiredMessagesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/RecoverExpiredMessagesTest.java new file mode 100644 index 0000000000..fb0296c4ce --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/RecoverExpiredMessagesTest.java @@ -0,0 +1,144 @@ +/** + * 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.broker.store; + +import java.io.File; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import junit.framework.Test; +import org.apache.activemq.broker.BrokerRestartTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.IOHelper; + +public class RecoverExpiredMessagesTest extends BrokerRestartTestSupport { + final ArrayList expected = new ArrayList(); + final ActiveMQDestination destination = new ActiveMQQueue("TEST"); + public PendingQueueMessageStoragePolicy queuePendingPolicy; + + @Override + protected void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + } + + public void initCombosForTestRecovery() throws Exception { + addCombinationValues("queuePendingPolicy", new PendingQueueMessageStoragePolicy[] {new FilePendingQueueMessageStoragePolicy(), new VMPendingQueueMessageStoragePolicy()}); + PersistenceAdapter[] persistenceAdapters = new PersistenceAdapter[] { + new KahaDBPersistenceAdapter(), + new JDBCPersistenceAdapter(JDBCPersistenceAdapter.createDataSource(IOHelper.getDefaultDataDirectory()), new OpenWireFormat()) + }; + for (PersistenceAdapter adapter : persistenceAdapters) { + adapter.setDirectory(new File(IOHelper.getDefaultDataDirectory())); + } + addCombinationValues("persistenceAdapter", persistenceAdapters); + } + + public void testRecovery() throws Exception { + sendSomeMessagesThatWillExpireIn5AndThenOne(); + + broker.stop(); + broker.waitUntilStopped(); + TimeUnit.SECONDS.sleep(6); + broker = createRestartedBroker(); + broker.start(); + + consumeExpected(); + } + + private void consumeExpected() throws Exception { + // Setup the consumer and receive the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + Message m = receiveMessage(connection); + assertNotNull("Should have received message " + expected.get(0) + " by now!", m); + assertEquals(expected.get(0), m.getMessageId().toString()); + MessageAck ack = createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE); + connection.send(ack); + + assertNoMessagesLeft(connection); + connection.request(closeConnectionInfo(connectionInfo)); + } + + private void sendSomeMessagesThatWillExpireIn5AndThenOne() throws Exception { + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + + int MESSAGE_COUNT = 10; + for(int i=0; i < MESSAGE_COUNT; i++) { + Message message = createMessage(producerInfo, destination); + message.setExpiration(System.currentTimeMillis()+5000); + message.setPersistent(true); + connection.send(message); + } + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + expected.add(message.getMessageId().toString()); + + connection.request(closeConnectionInfo(connectionInfo)); + } + + @Override + protected PolicyEntry getDefaultPolicy() { + PolicyEntry policy = super.getDefaultPolicy(); + policy.setPendingQueuePolicy(queuePendingPolicy); + policy.setExpireMessagesPeriod(0); + return policy; + } + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + super.configureBroker(broker); + broker.setPersistenceAdapter(persistenceAdapter); + } + + public static Test suite() { + return suite(RecoverExpiredMessagesTest.class); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/kahabroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/kahabroker.xml new file mode 100644 index 0000000000..4c8254b50d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/kahabroker.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/loadtester.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/loadtester.xml new file mode 100644 index 0000000000..6383e84f1b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/store/loadtester.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/DestinationsPluginTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/DestinationsPluginTest.java new file mode 100644 index 0000000000..d08fc5e076 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/DestinationsPluginTest.java @@ -0,0 +1,80 @@ +/** + * 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.broker.util; + + +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.command.ActiveMQDestination; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + + +public class DestinationsPluginTest { + + BrokerService broker; + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void shutdown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + protected BrokerService createBroker() { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.setPlugins(new BrokerPlugin[]{new DestinationsPlugin()}); + broker.setDataDirectory("target/test"); + return broker; + } + + @Test + public void testDestinationSave() throws Exception { + + BrokerView brokerView = broker.getAdminView(); + brokerView.addQueue("test-queue"); + + broker.stop(); + broker.waitUntilStopped(); + + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + + + ActiveMQDestination[] destinations = broker.getRegionBroker().getDestinations(); + for (ActiveMQDestination destination : destinations) { + if (destination.isQueue()) { + assertEquals("test-queue", destination.getPhysicalName()); + } + } + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/PluginBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/PluginBrokerTest.java new file mode 100644 index 0000000000..93618599da --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/PluginBrokerTest.java @@ -0,0 +1,88 @@ +/** + * 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.broker.util; + +import java.net.URI; + +import javax.jms.JMSException; +import javax.jms.Message; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.test.JmsTopicSendReceiveTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class PluginBrokerTest extends JmsTopicSendReceiveTest { + private static final Logger LOG = LoggerFactory.getLogger(PluginBrokerTest.class); + private BrokerService broker; + + protected void setUp() throws Exception { + broker = createBroker(); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/util/plugin-broker.xml"); + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + + protected void assertMessageValid(int index, Message message) + throws JMSException { + // check if broker path has been set + assertEquals("localhost", message.getStringProperty("BrokerPath")); + ActiveMQMessage amqMsg = (ActiveMQMessage)message; + if (index == 7) { + // check custom expiration + assertTrue("expiration is in range, depends on two distinct calls to System.currentTimeMillis", 1500 < amqMsg.getExpiration() - amqMsg.getTimestamp()); + } else if (index == 9) { + // check ceiling + assertTrue("expiration ceeling is in range, depends on two distinct calls to System.currentTimeMillis", 59500 < amqMsg.getExpiration() - amqMsg.getTimestamp()); + } else { + // check default expiration + assertEquals(1000, amqMsg.getExpiration() - amqMsg.getTimestamp()); + } + super.assertMessageValid(index, message); + } + + protected void sendMessage(int index, Message message) throws Exception { + if (index == 7) { + producer.send(producerDestination, message, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, 2000); + } else if (index == 9) { + producer.send(producerDestination, message, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, 200000); + } else { + super.sendMessage(index, message); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/RedeliveryPluginTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/RedeliveryPluginTest.java new file mode 100644 index 0000000000..dd12768f6d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/RedeliveryPluginTest.java @@ -0,0 +1,73 @@ +/** + * 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.broker.util; + +import junit.framework.TestCase; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ErrorBroker; +import org.apache.activemq.broker.region.policy.RedeliveryPolicyMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RedeliveryPluginTest extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(RedeliveryPluginTest.class); + RedeliveryPlugin underTest = new RedeliveryPlugin(); + + public void testInstallPluginValidation() throws Exception { + RedeliveryPolicyMap redeliveryPolicyMap = new RedeliveryPolicyMap(); + RedeliveryPolicy defaultEntry = new RedeliveryPolicy(); + defaultEntry.setInitialRedeliveryDelay(500); + redeliveryPolicyMap.setDefaultEntry(defaultEntry); + underTest.setRedeliveryPolicyMap(redeliveryPolicyMap); + + final BrokerService brokerService = new BrokerService(); + brokerService.setSchedulerSupport(false); + Broker broker = new ErrorBroker("hi") { + @Override + public BrokerService getBrokerService() { + return brokerService; + } + }; + + try { + underTest.installPlugin(broker); + fail("expect exception on no scheduler support"); + } catch (Exception expected) { + LOG.info("expected: " + expected); + } + + brokerService.setSchedulerSupport(true); + try { + underTest.installPlugin(broker); + fail("expect exception on small initial delay"); + } catch (Exception expected) { + LOG.info("expected: " + expected); + } + + defaultEntry.setInitialRedeliveryDelay(5000); + defaultEntry.setRedeliveryDelay(500); + brokerService.setSchedulerSupport(true); + try { + underTest.installPlugin(broker); + fail("expect exception on small redelivery delay"); + } catch (Exception expected) { + LOG.info("expected: " + expected); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/TimeStampingBrokerPluginTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/TimeStampingBrokerPluginTest.java new file mode 100644 index 0000000000..1a91f88dee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/TimeStampingBrokerPluginTest.java @@ -0,0 +1,197 @@ +/** + * 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.broker.util; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.IndividualDeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TimeStampingBrokerPluginTest extends TestCase { + + BrokerService broker; + TransportConnector tcpConnector; + MessageProducer producer; + MessageConsumer consumer; + Connection connection; + Session session; + Destination destination; + String queue = "TEST.FOO"; + long expiry = 500; + + @Before + public void setUp() throws Exception { + TimeStampingBrokerPlugin tsbp = new TimeStampingBrokerPlugin(); + tsbp.setZeroExpirationOverride(expiry); + tsbp.setTtlCeiling(expiry); + + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.setPlugins(new BrokerPlugin[] {tsbp}); + tcpConnector = broker.addConnector("tcp://localhost:0"); + + // Add policy and individual DLQ strategy + PolicyEntry policy = new PolicyEntry(); + DeadLetterStrategy strategy = new IndividualDeadLetterStrategy(); + strategy.setProcessExpired(true); + ((IndividualDeadLetterStrategy)strategy).setUseQueueForQueueMessages(true); + ((IndividualDeadLetterStrategy)strategy).setQueuePrefix("DLQ."); + strategy.setProcessNonPersistent(true); + policy.setDeadLetterStrategy(strategy); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + + broker.start(); + // Create a ConnectionFactory + ActiveMQConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(tcpConnector.getConnectUri()); + + // Create a Connection + connection = connectionFactory.createConnection(); + connection.start(); + + // Create a Session + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create the destination Queue + destination = session.createQueue(queue); + + // Create a MessageProducer from the Session to the Topic or Queue + producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + } + + @After + public void tearDown() throws Exception { + // Clean up + producer.close(); + consumer.close(); + session.close(); + connection.close(); + broker.stop(); + } + @Test + public void testExpirationSet() throws Exception { + + // Create a messages + Message sentMessage = session.createMessage(); + + // Tell the producer to send the message + long beforeSend = System.currentTimeMillis(); + producer.send(sentMessage); + + // Create a MessageConsumer from the Session to the Topic or Queue + consumer = session.createConsumer(destination); + + // Wait for a message + Message receivedMessage = consumer.receive(1000); + + // assert we got the same message ID we sent + assertEquals(sentMessage.getJMSMessageID(), receivedMessage.getJMSMessageID()); + + // assert message timestamp is in window + assertTrue("Expiration should be not null" + receivedMessage.getJMSExpiration() + "\n", Long.valueOf(receivedMessage.getJMSExpiration()) != null); + + // assert message expiration is in window + assertTrue("Before send: " + beforeSend + " Msg ts: " + receivedMessage.getJMSTimestamp() + " Msg Expiry: " + receivedMessage.getJMSExpiration(), beforeSend <= receivedMessage.getJMSExpiration() && receivedMessage.getJMSExpiration() <= (receivedMessage.getJMSTimestamp() + expiry)); + } + @Test + public void testExpirationCelingSet() throws Exception { + + // Create a messages + Message sentMessage = session.createMessage(); + // Tell the producer to send the message + long beforeSend = System.currentTimeMillis(); + long sendExpiry = beforeSend + (expiry*22); + sentMessage.setJMSExpiration(sendExpiry); + + producer.send(sentMessage); + + // Create a MessageConsumer from the Session to the Topic or Queue + consumer = session.createConsumer(destination); + + // Wait for a message + Message receivedMessage = consumer.receive(1000); + + // assert we got the same message ID we sent + assertEquals(sentMessage.getJMSMessageID(), receivedMessage.getJMSMessageID()); + + // assert message timestamp is in window + assertTrue("Expiration should be not null" + receivedMessage.getJMSExpiration() + "\n", Long.valueOf(receivedMessage.getJMSExpiration()) != null); + + // assert message expiration is in window + assertTrue("Sent expiry: " + sendExpiry + " Recv ts: " + receivedMessage.getJMSTimestamp() + " Recv expiry: " + receivedMessage.getJMSExpiration(), beforeSend <= receivedMessage.getJMSExpiration() && receivedMessage.getJMSExpiration() <= (receivedMessage.getJMSTimestamp() + expiry)); + } + + @Test + public void testExpirationDLQ() throws Exception { + + // Create a messages + Message sentMessage = session.createMessage(); + // Tell the producer to send the message + long beforeSend = System.currentTimeMillis(); + long sendExpiry = beforeSend + expiry; + sentMessage.setJMSExpiration(sendExpiry); + + producer.send(sentMessage); + + // Create a MessageConsumer from the Session to the Topic or Queue + consumer = session.createConsumer(destination); + + Thread.sleep(expiry+250); + + // Wait for a message + Message receivedMessage = consumer.receive(1000); + + // Message should roll to DLQ + assertNull(receivedMessage); + + // Close old consumer, setup DLQ listener + consumer.close(); + consumer = session.createConsumer(session.createQueue("DLQ."+queue)); + + // Get mesage from DLQ + receivedMessage = consumer.receive(1000); + + // assert we got the same message ID we sent + assertEquals(sentMessage.getJMSMessageID(), receivedMessage.getJMSMessageID()); + + // assert message timestamp is in window + //System.out.println("Recv: " + receivedMessage.getJMSExpiration()); + assertEquals("Expiration should be zero" + receivedMessage.getJMSExpiration() + "\n", receivedMessage.getJMSExpiration(), 0); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/TraceBrokerPathPluginTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/TraceBrokerPathPluginTest.java new file mode 100644 index 0000000000..35e9cdb840 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/util/TraceBrokerPathPluginTest.java @@ -0,0 +1,129 @@ +/** + * 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.broker.util; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests TraceBrokerPathPlugin by creating two brokers linked by a network connector, and checking to see if the consuming end receives the expected value in the trace property + * @author Raul Kripalani + * + */ +public class TraceBrokerPathPluginTest extends TestCase { + + BrokerService brokerA; + BrokerService brokerB; + TransportConnector tcpConnectorA; + TransportConnector tcpConnectorB; + MessageProducer producer; + MessageConsumer consumer; + Connection connectionA; + Connection connectionB; + Session sessionA; + Session sessionB; + String queue = "TEST.FOO"; + String traceProperty = "BROKER_PATH"; + + @Before + public void setUp() throws Exception { + TraceBrokerPathPlugin tbppA = new TraceBrokerPathPlugin(); + tbppA.setStampProperty(traceProperty); + + TraceBrokerPathPlugin tbppB = new TraceBrokerPathPlugin(); + tbppB.setStampProperty(traceProperty); + + brokerA = new BrokerService(); + brokerA.setBrokerName("brokerA"); + brokerA.setPersistent(false); + brokerA.setUseJmx(true); + brokerA.setPlugins(new BrokerPlugin[] {tbppA}); + tcpConnectorA = brokerA.addConnector("tcp://localhost:0"); + + brokerB = new BrokerService(); + brokerB.setBrokerName("brokerB"); + brokerB.setPersistent(false); + brokerB.setUseJmx(true); + brokerB.setPlugins(new BrokerPlugin[] {tbppB}); + tcpConnectorB = brokerB.addConnector("tcp://localhost:0"); + + brokerA.addNetworkConnector("static:(" + tcpConnectorB.getConnectUri().toString() + ")"); + + brokerB.start(); + brokerB.waitUntilStarted(); + brokerA.start(); + brokerA.waitUntilStarted(); + + // Initialise connection to A and MessageProducer + connectionA = new ActiveMQConnectionFactory(tcpConnectorA.getConnectUri()).createConnection(); + connectionA.start(); + sessionA = connectionA.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = sessionA.createProducer(sessionA.createQueue(queue)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + // Initialise connection to B and MessageConsumer + connectionB = new ActiveMQConnectionFactory(tcpConnectorB.getConnectUri()).createConnection(); + connectionB.start(); + sessionB = connectionB.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = sessionB.createConsumer(sessionB.createQueue(queue)); + + } + + @After + public void tearDown() throws Exception { + // Clean up + producer.close(); + consumer.close(); + sessionA.close(); + sessionB.close(); + connectionA.close(); + connectionB.close(); + brokerA.stop(); + brokerB.stop(); + } + + @Test + public void testTraceBrokerPathPlugin() throws Exception { + Message sentMessage = sessionA.createMessage(); + producer.send(sentMessage); + Message receivedMessage = consumer.receive(1000); + + // assert we got the message + assertNotNull(receivedMessage); + + // assert we got the same message ID we sent + assertEquals(sentMessage.getJMSMessageID(), receivedMessage.getJMSMessageID()); + + assertEquals("brokerA,brokerB", receivedMessage.getStringProperty(traceProperty)); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/CompositeQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/CompositeQueueTest.java new file mode 100644 index 0000000000..3621a14eec --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/CompositeQueueTest.java @@ -0,0 +1,132 @@ +/** + * 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.broker.virtual; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; +import org.apache.activemq.xbean.XBeanBrokerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class CompositeQueueTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(CompositeQueueTest.class); + + protected int total = 10; + protected Connection connection; + public String messageSelector1, messageSelector2 = null; + + + public void testVirtualTopicCreation() throws Exception { + if (connection == null) { + connection = createConnection(); + } + connection.start(); + + ConsumerBean messageList1 = new ConsumerBean(); + ConsumerBean messageList2 = new ConsumerBean(); + messageList1.setVerbose(true); + messageList2.setVerbose(true); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Destination producerDestination = getProducerDestination(); + Destination destination1 = getConsumer1Dsetination(); + Destination destination2 = getConsumer2Dsetination(); + + LOG.info("Sending to: " + producerDestination); + LOG.info("Consuming from: " + destination1 + " and " + destination2); + + MessageConsumer c1 = session.createConsumer(destination1, messageSelector1); + MessageConsumer c2 = session.createConsumer(destination2, messageSelector2); + + c1.setMessageListener(messageList1); + c2.setMessageListener(messageList2); + + // create topic producer + MessageProducer producer = session.createProducer(producerDestination); + assertNotNull(producer); + + for (int i = 0; i < total; i++) { + producer.send(createMessage(session, i)); + } + + assertMessagesArrived(messageList1, messageList2); + } + + protected void assertMessagesArrived(ConsumerBean messageList1, ConsumerBean messageList2) { + messageList1.assertMessagesArrived(total); + messageList2.assertMessagesArrived(total); + } + + protected TextMessage createMessage(Session session, int i) throws JMSException { + TextMessage textMessage = session.createTextMessage("message: " + i); + if (i % 2 != 0) { + textMessage.setStringProperty("odd", "yes"); + } else { + textMessage.setStringProperty("odd", "no"); + } + textMessage.setIntProperty("i", i); + return textMessage; + } + + protected Destination getConsumer1Dsetination() { + return new ActiveMQQueue("FOO"); + } + + protected Destination getConsumer2Dsetination() { + return new ActiveMQTopic("BAR"); + } + + protected Destination getProducerDestination() { + return new ActiveMQQueue("MY.QUEUE"); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + protected BrokerService createBroker() throws Exception { + XBeanBrokerFactory factory = new XBeanBrokerFactory(); + BrokerService answer = factory.createBroker(new URI(getBrokerConfigUri())); + return answer; + } + + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/virtual/composite-queue.xml"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/CompositeTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/CompositeTopicTest.java new file mode 100644 index 0000000000..991e3a56e0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/CompositeTopicTest.java @@ -0,0 +1,45 @@ +/** + * 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.broker.virtual; + +import javax.jms.Destination; + +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +/** + * + * + */ +public class CompositeTopicTest extends CompositeQueueTest { + + protected Destination getConsumer1Dsetination() { + return new ActiveMQQueue("FOO"); + } + + protected Destination getConsumer2Dsetination() { + return new ActiveMQTopic("BAR"); + } + + protected Destination getProducerDestination() { + return new ActiveMQTopic("MY.TOPIC"); + } + + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/virtual/composite-topic.xml"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/DestinationInterceptorDurableSubTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/DestinationInterceptorDurableSubTest.java new file mode 100644 index 0000000000..b6ba22d075 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/DestinationInterceptorDurableSubTest.java @@ -0,0 +1,282 @@ +/** + * 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.broker.virtual; + +import java.io.IOException; +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanServerConnection; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.apache.activemq.EmbeddedBrokerTestSupport; + +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.DestinationFilter; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.Message; +import org.apache.activemq.xbean.XBeanBrokerFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Test for AMQ-4571. + * checks that durable subscription is fully unregistered + * when using nested destination interceptors. + */ +public class DestinationInterceptorDurableSubTest extends EmbeddedBrokerTestSupport { + + private static final transient Logger LOG = LoggerFactory.getLogger(DestinationInterceptorDurableSubTest.class); + private MBeanServerConnection mbsc = null; + public static final String JMX_CONTEXT_BASE_NAME = "org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Topic,destinationName="; + + /** + * Tests AMQ-4571. + * @throws Exception + */ + public void testVirtualTopicRemoval() throws Exception { + + LOG.debug("Running testVirtualTopicRemoval()"); + String clientId1 = "myId1"; + String clientId2 = "myId2"; + + Connection conn = null; + Session session = null; + + try { + assertTrue(broker.isStarted()); + + // create durable sub 1 + conn = createConnection(); + conn.setClientID(clientId1); + conn.start(); + session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + // Topic topic = session.createTopic(destination.getPhysicalName()); + TopicSubscriber sub1 = session.createDurableSubscriber((Topic) destination, clientId1); + + // create durable sub 2 + TopicSubscriber sub2 = session.createDurableSubscriber((Topic) destination, clientId2); + + // verify two subs registered in JMX + assertSubscriptionCount(destination.getPhysicalName(), 2); + assertTrue(isSubRegisteredInJmx(destination.getPhysicalName(), clientId1)); + assertTrue(isSubRegisteredInJmx(destination.getPhysicalName(), clientId2)); + + // delete sub 1 + sub1.close(); + session.unsubscribe(clientId1); + + // verify only one sub registered in JMX + assertSubscriptionCount(destination.getPhysicalName(), 1); + assertFalse(isSubRegisteredInJmx(destination.getPhysicalName(), clientId1)); + assertTrue(isSubRegisteredInJmx(destination.getPhysicalName(), clientId2)); + + // delete sub 2 + sub2.close(); + session.unsubscribe(clientId2); + + // verify no sub registered in JMX + assertSubscriptionCount(destination.getPhysicalName(), 0); + assertFalse(isSubRegisteredInJmx(destination.getPhysicalName(), clientId1)); + assertFalse(isSubRegisteredInJmx(destination.getPhysicalName(), clientId2)); + } finally { + session.close(); + conn.close(); + } + } + + + /** + * Connects to broker using JMX + * @return The JMX connection + * @throws IOException in case of any errors + */ + protected MBeanServerConnection connectJMXBroker() throws IOException { + // connect to broker via JMX + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:1299/jmxrmi"); + JMXConnector jmxc = JMXConnectorFactory.connect(url, null); + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + LOG.debug("JMX connection established"); + return mbsc; + } + + /** + * Asserts that the Subscriptions JMX attribute of a topic has the expected + * count. + * @param topicName name of the topic destination + * @param expectedCount expected number of subscriptions + * @return + */ + protected boolean assertSubscriptionCount(String topicName, int expectedCount) { + try { + if (mbsc == null) { + mbsc = connectJMXBroker(); + } + // query broker queue size + ObjectName[] tmp = (ObjectName[])mbsc.getAttribute(new ObjectName(JMX_CONTEXT_BASE_NAME + topicName), "Subscriptions"); + assertEquals(expectedCount, tmp.length); + } catch (Exception ex) { + LOG.error(ex.getMessage()); + return false; + } + return true; + } + + /** + * Checks if a subscriptions for topic topicName with subName is registered in JMX + * + * @param topicName physical name of topic destination (excluding prefix 'topic://') + * @param subName name of the durable subscription + * @return true if registered, false otherwise + */ + protected boolean isSubRegisteredInJmx(String topicName, String subName) { + + try { + if (mbsc == null) { + mbsc = connectJMXBroker(); + } + + // A durable sub is registered under the Subscriptions JMX attribute of the topic and + // as its own ObjectInstance under the topic's Consumer namespace. + // AMQ-4571 only removed the latter not the former on unsubscribe(), so we need + // to check against both. + ObjectName[] names = (ObjectName[])mbsc.getAttribute(new ObjectName(JMX_CONTEXT_BASE_NAME + topicName), "Subscriptions"); + ObjectInstance instance = (ObjectInstance)mbsc.getObjectInstance( + new ObjectName(JMX_CONTEXT_BASE_NAME + + topicName + + ",endpoint=Consumer,clientId=myId1,consumerId=Durable(myId1_" + + subName + + ")") + ); + + if (instance == null) + return false; + + for (int i=0; i < names.length; i++) { + if (names[i].toString().contains(subName)) + return true; + } + } catch (InstanceNotFoundException ine) { + //this may be expected so log at info level + LOG.info(ine.toString()); + return false; + } + catch (Exception ex) { + LOG.error(ex.toString()); + return false; + } + return false; + } + + + protected void tearDown() throws Exception { + super.tearDown(); + } + + + protected BrokerService createBroker() throws Exception { + XBeanBrokerFactory factory = new XBeanBrokerFactory(); + BrokerService answer = factory.createBroker(new URI(getBrokerConfigUri())); + + // lets disable persistence as we are a test + answer.setPersistent(false); + useTopic = true; + return answer; + } + + + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/virtual/virtual-topics-and-interceptor.xml"; + } + + + /** + * Simple but custom topic interceptor. + * To be used for testing nested interceptors in conjunction with + * virtual topic interceptor. + */ + public static class SimpleDestinationInterceptor implements DestinationInterceptor { + + private final Logger LOG = LoggerFactory.getLogger(SimpleDestinationInterceptor.class); + private BrokerService broker; + + public SimpleDestinationInterceptor() { + } + + /* (non-Javadoc) + * @see org.apache.activemq.broker.BrokerServiceAware#setBrokerService(org.apache.activemq.broker.BrokerService) + */ + public void setBrokerService(BrokerService brokerService) { + LOG.info("setBrokerService()"); + this.broker = brokerService; + } + + /* (non-Javadoc) + * @see org.apache.activemq.broker.region.DestinationInterceptor#intercept(org.apache.activemq.broker.region.Destination) + */ + public Destination intercept(final Destination destination) { + LOG.info("intercept({})", destination.getName()); + + if (!destination.getActiveMQDestination().getPhysicalName().startsWith("ActiveMQ")) { + return new DestinationFilter(destination) { + public void send(ProducerBrokerExchange context, Message message) throws Exception { + // Send message to Destination + if (LOG.isDebugEnabled()) { + LOG.debug("SimpleDestinationInterceptor: Sending message to destination:" + + this.getActiveMQDestination().getPhysicalName()); + } + // message.setDestination(destination.getActiveMQDestination()); + super.send(context, message); + } + }; + } + return destination; + } + + + /* (non-Javadoc) + * @see org.apache.activemq.broker.region.DestinationInterceptor#remove(org.apache.activemq.broker.region.Destination) + */ + public void remove(Destination destination) { + LOG.info("remove({})", destination.getName()); + this.broker = null; + } + + + /* (non-Javadoc) + * @see org.apache.activemq.broker.region.DestinationInterceptor#create(org.apache.activemq.broker.Broker, org.apache.activemq.broker.ConnectionContext, org.apache.activemq.command.ActiveMQDestination) + */ + public void create(Broker broker, ConnectionContext context, ActiveMQDestination destination) throws Exception { + LOG.info("create("+ broker.getBrokerName() + ", " + context.toString() + ", " + destination.getPhysicalName()); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/FilteredQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/FilteredQueueTest.java new file mode 100644 index 0000000000..17a870638c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/FilteredQueueTest.java @@ -0,0 +1,36 @@ +/** + * 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.broker.virtual; + +import org.apache.activemq.spring.ConsumerBean; + +/** + * + */ +public class FilteredQueueTest extends CompositeQueueTest { + + @Override + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/virtual/filtered-queue.xml"; + } + + @Override + protected void assertMessagesArrived(ConsumerBean messageList1, ConsumerBean messageList2) { + messageList1.assertMessagesArrived(total / 2); + messageList2.assertMessagesArrived(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueCorrectMemoryUsageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueCorrectMemoryUsageTest.java new file mode 100644 index 0000000000..4c19c7b254 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueCorrectMemoryUsageTest.java @@ -0,0 +1,165 @@ +/** + * 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.broker.virtual; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.virtual.MirroredQueue; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.usage.MemoryUsage; +import org.apache.activemq.usage.StoreUsage; +import org.apache.activemq.usage.SystemUsage; +import org.apache.activemq.usage.TempUsage; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.Assert; + +/** + * This test will determine that the producer flow control does not kick in. + * The original MirroredQueue implementation was causing the queue to update + * the topic memory usage instead of the queue memory usage. + * The reason is that the message memory usage instance will not be updated + * unless it is null. This was the case when the message was initially sent + * to the topic but then it was non-null when it was being sent to the queue. + * When the region destination was set, the associated memory usage was not + * updated to the passed queue destination and thus the memory usage of the + * topic was being updated instead. + * + * @author Claudio Corsi + */ +public class MirroredQueueCorrectMemoryUsageTest extends EmbeddedBrokerTestSupport { + + private static final Logger logger = LoggerFactory.getLogger(MirroredQueueCorrectMemoryUsageTest.class); + + private static final long ONE_MB = 0x0100000; + private static final long TEN_MB = ONE_MB * 10; + private static final long TWENTY_MB = TEN_MB * 2; + + private static final String CREATED_STATIC_FOR_PERSISTENT = "created.static.for.persistent"; + + @Override + protected boolean isPersistent() { + return true; + } + + @Override + protected BrokerService createBroker() throws Exception { + // Create the broker service instance.... + BrokerService broker = super.createBroker(); + // Create and add the mirrored queue destination interceptor .... + DestinationInterceptor[] destinationInterceptors = new DestinationInterceptor[1]; + MirroredQueue mq = new MirroredQueue(); + mq.setCopyMessage(true); + mq.setPrefix(""); + mq.setPostfix(".qmirror"); + destinationInterceptors[0] = mq; + broker.setDestinationInterceptors(destinationInterceptors); + // Create the destination policy for the topics and queues + PolicyMap policyMap = new PolicyMap(); + List entries = new LinkedList(); + // Create Topic policy entry + PolicyEntry policyEntry = new PolicyEntry(); + super.useTopic = true; + ActiveMQDestination destination = super.createDestination(">"); + Assert.isTrue(destination.isTopic(), "Created destination was not a topic"); + policyEntry.setDestination(destination); + policyEntry.setProducerFlowControl(true); + policyEntry.setMemoryLimit(ONE_MB); // x10 + entries.add(policyEntry); + // Create Queue policy entry + policyEntry = new PolicyEntry(); + super.useTopic = false; + destination = super.createDestination(CREATED_STATIC_FOR_PERSISTENT); + Assert.isTrue(destination.isQueue(), "Created destination was not a queue"); + policyEntry.setDestination(destination); + policyEntry.setProducerFlowControl(true); + policyEntry.setMemoryLimit(TEN_MB); + entries.add(policyEntry); + policyMap.setPolicyEntries(entries); + broker.setDestinationPolicy(policyMap); + // Set destinations + broker.setDestinations(new ActiveMQDestination[] { destination }); + // Set system usage + SystemUsage memoryManager = new SystemUsage(); + MemoryUsage memoryUsage = new MemoryUsage(); + memoryUsage.setLimit(TEN_MB); + memoryManager.setMemoryUsage(memoryUsage); + StoreUsage storeUsage = new StoreUsage(); + storeUsage.setLimit(TWENTY_MB); + memoryManager.setStoreUsage(storeUsage); + TempUsage tempDiskUsage = new TempUsage(); + tempDiskUsage.setLimit(TEN_MB); + memoryManager.setTempUsage(tempDiskUsage); + broker.setSystemUsage(memoryManager); + // Set the persistent adapter + KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); + persistenceAdapter.setJournalMaxFileLength((int)TEN_MB); + // Delete all current messages... + IOHelper.deleteFile(persistenceAdapter.getDirectory()); + broker.setPersistenceAdapter(persistenceAdapter); + return broker; + } + + @Before + protected void setUp() throws Exception { + super.setUp(); + } + + @After + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Test(timeout=40000) + public void testNoMemoryUsageIncreaseForTopic() throws Exception { + Connection connection = super.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination destination = session.createQueue(CREATED_STATIC_FOR_PERSISTENT); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + char[] m = new char[1024]; + Arrays.fill(m, 'x'); + // create some messages that have 1k each + for (int i = 1; i < 12000; i++) { + producer.send(session.createTextMessage(new String(m))); + logger.debug("Sent message: " + i); + } + producer.close(); + session.close(); + connection.stop(); + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueTest.java new file mode 100644 index 0000000000..acbe3b99a6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueTest.java @@ -0,0 +1,116 @@ +/** + * 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.broker.virtual; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class MirroredQueueTest extends EmbeddedBrokerTestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(MirroredQueueTest.class); + private Connection connection; + + public void testSendingToQueueIsMirrored() throws Exception { + if (connection == null) { + connection = createConnection(); + } + connection.start(); + + ConsumerBean messageList = new ConsumerBean(); + messageList.setVerbose(true); + + Destination consumeDestination = createConsumeDestination(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + LOG.info("Consuming from: " + consumeDestination); + + MessageConsumer c1 = session.createConsumer(consumeDestination); + c1.setMessageListener(messageList); + + // create topic producer + ActiveMQQueue sendDestination = new ActiveMQQueue(getQueueName()); + LOG.info("Sending to: " + sendDestination); + + MessageProducer producer = session.createProducer(sendDestination); + assertNotNull(producer); + + int total = 10; + for (int i = 0; i < total; i++) { + producer.send(session.createTextMessage("message: " + i)); + } + + ///Thread.sleep(1000000); + + messageList.assertMessagesArrived(total); + + LOG.info("Received: " + messageList); + } + + public void testTempMirroredQueuesClearDown() throws Exception{ + if (connection == null) { + connection = createConnection(); + } + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue tempQueue = session.createTemporaryQueue(); + RegionBroker rb = (RegionBroker) broker.getBroker().getAdaptor( + RegionBroker.class); + assertTrue(rb.getDestinationMap().size()==5); + tempQueue.delete(); + assertTrue(rb.getDestinationMap().size()==4); + } + + protected Destination createConsumeDestination() { + return new ActiveMQTopic("VirtualTopic.Mirror." + getQueueName()); + } + + protected String getQueueName() { + return "My.Queue"; + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseMirroredQueues(true); + answer.setPersistent(isPersistent()); + answer.addConnector(bindAddress); + return answer; + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueUsingVirtualTopicQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueUsingVirtualTopicQueueTest.java new file mode 100644 index 0000000000..f8cccf495f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/MirroredQueueUsingVirtualTopicQueueTest.java @@ -0,0 +1,34 @@ +/** + * 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.broker.virtual; + +import javax.jms.Destination; + +import org.apache.activemq.command.ActiveMQQueue; + +/** + * + * + */ +public class MirroredQueueUsingVirtualTopicQueueTest extends MirroredQueueTest { + + @Override + protected Destination createConsumeDestination() { + String queueName = "Consumer.A.VirtualTopic.Mirror." + getQueueName(); + return new ActiveMQQueue(queueName); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualDestPerfTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualDestPerfTest.java new file mode 100644 index 0000000000..b822f5dca9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualDestPerfTest.java @@ -0,0 +1,209 @@ +/** + * 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.broker.virtual; + + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.virtual.CompositeTopic; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.command.ActiveMQBytesMessage; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.ByteSequence; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +public class VirtualDestPerfTest { + + private static final Logger LOG = LoggerFactory.getLogger(VirtualDestPerfTest.class); + public int messageSize = 5*1024; + public int messageCount = 10000; + ActiveMQTopic target = new ActiveMQTopic("target"); + BrokerService brokerService; + ActiveMQConnectionFactory connectionFactory; + + @Test + @Ignore("comparison test - 'new' no wait on future with async send broker side is always on") + public void testAsyncSendBurstToFillCache() throws Exception { + startBroker(4, true, true); + connectionFactory.setUseAsyncSend(true); + + // a burst of messages to fill the cache + messageCount = 22000; + messageSize = 10*1024; + + LinkedHashMap results = new LinkedHashMap(); + + final ActiveMQQueue queue = new ActiveMQQueue("targetQ"); + for (Integer numThreads : new Integer[]{1, 2}) { + ExecutorService executor = Executors.newFixedThreadPool(numThreads); + final AtomicLong numMessagesToSend = new AtomicLong(messageCount); + purge(); + long startTime = System.currentTimeMillis(); + for (int i=0;i resultsT = new LinkedHashMap(); + LinkedHashMap resultsF = new LinkedHashMap(); + + for (int i=2;i<11;i++) { + for (Boolean concurrent : new Boolean[]{true, false}) { + startBroker(i, concurrent, false); + + long startTime = System.currentTimeMillis(); + produceMessages(new AtomicLong(messageCount), target); + long endTime = System.currentTimeMillis(); + long seconds = (endTime - startTime) / 1000; + LOG.info("For routes {} duration {}", i, seconds); + if (concurrent) { + resultsT.put(i, seconds); + } else { + resultsF.put(i, seconds); + } + brokerService.stop(); + brokerService.waitUntilStopped(); + } + } + LOG.info("results T{} F{}", resultsT, resultsF); + LOG.info("http://www.chartgo.com/samples.do?chart=line&border=1&show3d=0&width=600&height=500&roundedge=1&transparency=1&legend=1&title=Send:10k::Concurrent-v-Serial&xtitle=routes&ytitle=Duration(seconds)&chrtbkgndcolor=white&threshold=0.0&lang=en" + + "&xaxis1=" + toStr(resultsT.keySet()) + + "&yaxis1=" + toStr(resultsT.values()) + + "&group1=concurrent" + + "&xaxis2=" + toStr(resultsF.keySet()) + + "&yaxis2=" + toStr(resultsF.values()) + + "&group2=serial" + + "&from=linejsp"); + } + + private String toStr(Collection set) { + return set.toString().replace(",","%0D%0A").replace("[","").replace("]","").replace(" ", ""); + } + + protected void produceMessages(AtomicLong messageCount, ActiveMQDestination destination) throws Exception { + final ByteSequence payLoad = new ByteSequence(new byte[messageSize]); + Connection connection = connectionFactory.createConnection(); + MessageProducer messageProducer = connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createProducer(destination); + messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + ActiveMQBytesMessage message = new ActiveMQBytesMessage(); + message.setContent(payLoad); + while (messageCount.decrementAndGet() >= 0) { + messageProducer.send(message); + } + connection.close(); + } + + private void startBroker(int fanoutCount, boolean concurrentSend, boolean concurrentStoreAndDispatchQueues) throws Exception { + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setUseVirtualTopics(true); + brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.setAdvisorySupport(false); + PolicyMap destPolicyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setExpireMessagesPeriod(0); + defaultEntry.setOptimizedDispatch(true); + defaultEntry.setCursorMemoryHighWaterMark(110); + destPolicyMap.setDefaultEntry(defaultEntry); + brokerService.setDestinationPolicy(destPolicyMap); + + CompositeTopic route = new CompositeTopic(); + route.setName("target"); + route.setForwardOnly(true); + route.setConcurrentSend(concurrentSend); + Collection routes = new ArrayList(); + for (int i=0; i + * + * + * + */ + @Test + public void testVirtualTopicSubscriberDeadLetterQueue() throws Exception { + + TestConsumer consumer1 = null; + TestConsumer consumer2 = null; + TestConsumer consumer3 = null; + TestConsumer dlqConsumer1 = null; + TestConsumer dlqConsumer2 = null; + TestConsumer dlqConsumer3 = null; + + try { + + // The first 2 consumers will rollback, ultimately causing messages + // to land on the DLQ + consumer1 = new TestConsumer(consumer1Prefix + virtualTopicName, false, numberMessages, true); + thread(consumer1, false); + + consumer2 = new TestConsumer(consumer2Prefix + virtualTopicName, false, numberMessages, true); + thread(consumer2, false); + + // TestConsumer that does not throw exceptions, messages should not + // land on DLQ + consumer3 = new TestConsumer(consumer3Prefix + virtualTopicName, false, numberMessages, false); + thread(consumer3, false); + + // TestConsumer to read the expected Dead Letter Queue + dlqConsumer1 = new TestConsumer(dlqPrefix + consumer1Prefix + virtualTopicName, false, numberMessages, false); + thread(dlqConsumer1, false); + + dlqConsumer2 = new TestConsumer(dlqPrefix + consumer2Prefix + virtualTopicName, false, numberMessages, false); + thread(dlqConsumer2, false); + + dlqConsumer3 = new TestConsumer(dlqPrefix + consumer3Prefix + virtualTopicName, false, numberMessages, false); + thread(dlqConsumer3, false); + + // Give the consumers a second to start + Thread.sleep(1000); + + // Start the producer + TestProducer producer = new TestProducer(virtualTopicName, true, numberMessages); + thread(producer, false); + + assertTrue("sent all producer messages in time, count is: " + producer.getLatch().getCount(), producer.getLatch().await(10, TimeUnit.SECONDS)); + LOG.info("producer successful, count = " + producer.getLatch().getCount()); + + assertTrue("remaining consumer1 count should be zero, is: " + consumer1.getLatch().getCount(), consumer1.getLatch().await(10, TimeUnit.SECONDS)); + LOG.info("consumer1 successful, count = " + consumer1.getLatch().getCount()); + + assertTrue("remaining consumer2 count should be zero, is: " + consumer2.getLatch().getCount(), consumer2.getLatch().await(10, TimeUnit.SECONDS)); + LOG.info("consumer2 successful, count = " + consumer2.getLatch().getCount()); + + assertTrue("remaining consumer3 count should be zero, is: " + consumer3.getLatch().getCount(), consumer3.getLatch().await(10, TimeUnit.SECONDS)); + LOG.info("consumer3 successful, count = " + consumer3.getLatch().getCount()); + + assertTrue("remaining dlqConsumer1 count should be zero, is: " + dlqConsumer1.getLatch().getCount(), + dlqConsumer1.getLatch().await(10, TimeUnit.SECONDS)); + LOG.info("dlqConsumer1 successful, count = " + dlqConsumer1.getLatch().getCount()); + + assertTrue("remaining dlqConsumer2 count should be zero, is: " + dlqConsumer2.getLatch().getCount(), + dlqConsumer2.getLatch().await(10, TimeUnit.SECONDS)); + LOG.info("dlqConsumer2 successful, count = " + dlqConsumer2.getLatch().getCount()); + + assertTrue("remaining dlqConsumer3 count should be " + numberMessages + ", is: " + dlqConsumer3.getLatch().getCount(), dlqConsumer3.getLatch() + .getCount() == numberMessages); + LOG.info("dlqConsumer2 successful, count = " + dlqConsumer2.getLatch().getCount()); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + // Tell consumers to stop (don't read any more messages after this) + if (consumer1 != null) + consumer1.setStop(true); + if (consumer2 != null) + consumer2.setStop(true); + if (consumer3 != null) + consumer3.setStop(true); + if (dlqConsumer1 != null) + dlqConsumer1.setStop(true); + if (dlqConsumer2 != null) + dlqConsumer2.setStop(true); + if (dlqConsumer3 != null) + dlqConsumer3.setStop(true); + } + } + + private static Thread thread(Runnable runnable, boolean daemon) { + Thread brokerThread = new Thread(runnable); + brokerThread.setDaemon(daemon); + brokerThread.start(); + return brokerThread; + } + + private class TestProducer implements Runnable { + private String destinationName = null; + private boolean isTopic = true; + private int numberMessages = 0; + private CountDownLatch latch = null; + + public TestProducer(String destinationName, boolean isTopic, int numberMessages) { + this.destinationName = destinationName; + this.isTopic = isTopic; + this.numberMessages = numberMessages; + latch = new CountDownLatch(numberMessages); + } + + public CountDownLatch getLatch() { + return latch; + } + + public void run() { + ActiveMQConnectionFactory connectionFactory = null; + ActiveMQConnection connection = null; + ActiveMQSession session = null; + Destination destination = null; + + try { + LOG.info("Started TestProducer for destination (" + destinationName + ")"); + + connectionFactory = new ActiveMQConnectionFactory(jmsConnectionURI); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + session = (ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + if (isTopic) { + destination = session.createTopic(this.destinationName); + } else { + destination = session.createQueue(this.destinationName); + } + + // Create a MessageProducer from the Session to the Topic or + // Queue + ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + for (int i = 0; i < numberMessages; i++) { + TextMessage message = (TextMessage) session.createTextMessage("I am a message :: " + String.valueOf(i)); + try { + producer.send(message); + + } catch (Exception deeperException) { + LOG.info("Producer for destination (" + destinationName + ") Caught: " + deeperException); + } + + latch.countDown(); + Thread.sleep(1000); + } + + LOG.info("Finished TestProducer for destination (" + destinationName + ")"); + + } catch (Exception e) { + LOG.error("Terminating TestProducer(" + destinationName + ")Caught: " + e); + e.printStackTrace(); + + } finally { + try { + // Clean up + if (session != null) + session.close(); + if (connection != null) + connection.close(); + + } catch (Exception e) { + e.printStackTrace(); + LOG.error("Closing connection/session (" + destinationName + ")Caught: " + e); + } + } + } + } + + private class TestConsumer implements Runnable, ExceptionListener, MessageListener { + private String destinationName = null; + private boolean isTopic = true; + private CountDownLatch latch = null; + private int maxRedeliveries = 0; + private int receivedMessageCounter = 0; + private boolean bFakeFail = false; + private boolean bStop = false; + + private ActiveMQConnectionFactory connectionFactory = null; + private ActiveMQConnection connection = null; + private Session session = null; + private MessageConsumer consumer = null; + + public TestConsumer(String destinationName, boolean isTopic, int expectedNumberMessages, boolean bFakeFail) { + this.destinationName = destinationName; + this.isTopic = isTopic; + latch = new CountDownLatch(expectedNumberMessages * (this.bFakeFail ? (maxRedeliveries + 1) : 1)); + this.bFakeFail = bFakeFail; + } + + public CountDownLatch getLatch() { + return latch; + } + + public void run() { + + try { + LOG.info("Started TestConsumer for destination (" + destinationName + ")"); + + connectionFactory = new ActiveMQConnectionFactory(jmsConnectionURI); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(true, Session.SESSION_TRANSACTED); + + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(1); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(maxRedeliveries); + + connection.setExceptionListener(this); + + Destination destination = null; + if (isTopic) { + destination = session.createTopic(destinationName); + } else { + destination = session.createQueue(destinationName); + } + + consumer = session.createConsumer(destination); + consumer.setMessageListener(this); + + while (!bStop) { + Thread.sleep(100); + } + + LOG.info("Finished TestConsumer for destination name (" + destinationName + ") remaining " + this.latch.getCount() + " messages " + + this.toString()); + + } catch (Exception e) { + LOG.error("Consumer (" + destinationName + ") Caught: " + e); + e.printStackTrace(); + } finally { + try { + // Clean up + if (consumer != null) + consumer.close(); + if (session != null) + session.close(); + if (connection != null) + connection.close(); + + } catch (Exception e) { + e.printStackTrace(); + LOG.error("Closing connection/session (" + destinationName + ")Caught: " + e); + } + } + } + + public synchronized void onException(JMSException ex) { + ex.printStackTrace(); + LOG.error("Consumer for destination, (" + destinationName + "), JMS Exception occured. Shutting down client."); + } + + public synchronized void setStop(boolean bStop) { + this.bStop = bStop; + } + + public synchronized void onMessage(Message message) { + receivedMessageCounter++; + latch.countDown(); + + LOG.info("Consumer for destination (" + destinationName + ") latch countdown: " + latch.getCount() + " :: Number messages received " + + this.receivedMessageCounter); + + try { + LOG.info("Consumer for destination (" + destinationName + ") Received message id :: " + message.getJMSMessageID()); + + if (!bFakeFail) { + LOG.info("Consumer on destination " + destinationName + " committing JMS Session for message: " + message.toString()); + session.commit(); + } else { + LOG.info("Consumer on destination " + destinationName + " rolling back JMS Session for message: " + message.toString()); + session.rollback(); // rolls back all the consumed messages + // on the session to + } + + } catch (JMSException ex) { + ex.printStackTrace(); + LOG.error("Error reading JMS Message from destination " + destinationName + "."); + } + } + } + + private static void purgeDestination(String destination) throws Exception { + final Queue dest = (Queue) ((RegionBroker) broker.getRegionBroker()).getQueueRegion().getDestinationMap().get(new ActiveMQQueue(destination)); + dest.purge(); + assertEquals(0, dest.getDestinationStatistics().getMessages().getCount()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicDisconnectSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicDisconnectSelectorTest.java new file mode 100644 index 0000000000..8b95345523 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicDisconnectSelectorTest.java @@ -0,0 +1,185 @@ +/** + * 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.broker.virtual; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; +import org.apache.activemq.xbean.XBeanBrokerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test case for https://issues.apache.org/jira/browse/AMQ-3004 + */ + +public class VirtualTopicDisconnectSelectorTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(VirtualTopicDisconnectSelectorTest.class); + protected Connection connection; + + public void testVirtualTopicSelectorDisconnect() throws Exception { + testVirtualTopicDisconnect("odd = 'no'", 3000, 1500); + } + + public void testVirtualTopicNoSelectorDisconnect() throws Exception { + testVirtualTopicDisconnect(null, 3000, 3000); + } + + public void testVirtualTopicDisconnect(String messageSelector, int total , int expected) throws Exception { + if (connection == null) { + connection = createConnection(); + } + connection.start(); + + final ConsumerBean messageList = new ConsumerBean(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + Destination producerDestination = getProducerDestination(); + Destination destination = getConsumerDsetination(); + + LOG.info("Sending to: " + producerDestination); + LOG.info("Consuming from: " + destination ); + + MessageConsumer consumer = createConsumer(session, destination, messageSelector); + + MessageListener listener = new MessageListener(){ + public void onMessage(Message message){ + messageList.onMessage(message); + try { + message.acknowledge(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + }; + + consumer.setMessageListener(listener); + + + // create topic producer + MessageProducer producer = session.createProducer(producerDestination); + assertNotNull(producer); + + int disconnectCount = total/3; + int reconnectCount = (total * 2)/3; + + for (int i = 0; i < total; i++) { + producer.send(createMessage(session, i)); + + if (i==disconnectCount){ + consumer.close(); + } + if (i==reconnectCount){ + consumer = createConsumer(session, destination, messageSelector); + consumer.setMessageListener(listener); + } + } + + assertMessagesArrived(messageList, expected ,10000); + } + + protected Destination getConsumerDsetination() { + return new ActiveMQQueue("Consumer.VirtualTopic.TEST"); + } + + + protected Destination getProducerDestination() { + return new ActiveMQTopic("VirtualTopic.TEST"); + } + + protected void setUp() throws Exception { + super.setUp(); + } + + protected MessageConsumer createConsumer(Session session, Destination destination, String messageSelector) throws JMSException { + if (messageSelector != null) { + return session.createConsumer(destination, messageSelector); + } else { + return session.createConsumer(destination); + } + } + + protected TextMessage createMessage(Session session, int i) throws JMSException { + TextMessage textMessage = session.createTextMessage("message: " + i); + if (i % 2 != 0) { + textMessage.setStringProperty("odd", "yes"); + } else { + textMessage.setStringProperty("odd", "no"); + } + textMessage.setIntProperty("i", i); + return textMessage; + } + + + + protected void assertMessagesArrived(ConsumerBean messageList, int expected, long timeout) { + messageList.assertMessagesArrived(expected,timeout); + + messageList.flushMessages(); + + + LOG.info("validate no other messages on queues"); + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Destination destination1 = getConsumerDsetination(); + + MessageConsumer c1 = session.createConsumer(destination1, null); + c1.setMessageListener(messageList); + + + LOG.info("send one simple message that should go to both consumers"); + MessageProducer producer = session.createProducer(getProducerDestination()); + assertNotNull(producer); + + producer.send(session.createTextMessage("Last Message")); + + messageList.assertMessagesArrived(1); + + } catch (JMSException e) { + e.printStackTrace(); + fail("unexpeced ex while waiting for last messages: " + e); + } + } + + + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/virtual/disconnected-selector.xml"; + } + + protected BrokerService createBroker() throws Exception { + XBeanBrokerFactory factory = new XBeanBrokerFactory(); + BrokerService answer = factory.createBroker(new URI(getBrokerConfigUri())); + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicPubSubTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicPubSubTest.java new file mode 100644 index 0000000000..42e6e60e7c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicPubSubTest.java @@ -0,0 +1,129 @@ +/** + * 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.broker.virtual; + +import java.util.Vector; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; + +/** + * + * + */ +public class VirtualTopicPubSubTest extends EmbeddedBrokerTestSupport { + + private Vector connections = new Vector(); + public int ackMode = Session.AUTO_ACKNOWLEDGE; + + public static Test suite() { + return suite(VirtualTopicPubSubTest.class); + } + + public void initCombosForTestVirtualTopicCreation() { + addCombinationValues("ackMode", new Object[] {new Integer(Session.AUTO_ACKNOWLEDGE), new Integer(Session.CLIENT_ACKNOWLEDGE) }); + } + + private boolean doneTwice = false; + + public void testVirtualTopicCreation() throws Exception { + doTestVirtualTopicCreation(10); + } + + public void doTestVirtualTopicCreation(int total) throws Exception { + + ConsumerBean messageList = new ConsumerBean() { + public synchronized void onMessage(Message message) { + super.onMessage(message); + if (ackMode == Session.CLIENT_ACKNOWLEDGE) { + try { + message.acknowledge(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + + } + }; + messageList.setVerbose(true); + + String queueAName = getVirtualTopicConsumerName(); + // create consumer 'cluster' + ActiveMQQueue queue1 = new ActiveMQQueue(queueAName); + ActiveMQQueue queue2 = new ActiveMQQueue(queueAName); + + Session session = createStartAndTrackConnection().createSession(false, ackMode); + MessageConsumer c1 = session.createConsumer(queue1); + + session = createStartAndTrackConnection().createSession(false, ackMode); + MessageConsumer c2 = session.createConsumer(queue2); + + c1.setMessageListener(messageList); + c2.setMessageListener(messageList); + + // create topic producer + Session producerSession = createStartAndTrackConnection().createSession(false, ackMode); + MessageProducer producer = producerSession.createProducer(new ActiveMQTopic(getVirtualTopicName())); + assertNotNull(producer); + + for (int i = 0; i < total; i++) { + producer.send(producerSession.createTextMessage("message: " + i)); + } + + messageList.assertMessagesArrived(total); + + // do twice so we confirm messages do not get redelivered after client acknowledgement + if( doneTwice == false ) { + doneTwice = true; + doTestVirtualTopicCreation(0); + } + } + + private Connection createStartAndTrackConnection() throws Exception { + Connection connection = createConnection(); + connection.start(); + connections.add(connection); + return connection; + } + + protected String getVirtualTopicName() { + return "VirtualTopic.TEST"; + } + + protected String getVirtualTopicConsumerName() { + return "Consumer.A.VirtualTopic.TEST"; + } + + + protected void tearDown() throws Exception { + for (Connection connection: connections) { + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicPubSubUsingXBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicPubSubUsingXBeanTest.java new file mode 100644 index 0000000000..69523313d5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicPubSubUsingXBeanTest.java @@ -0,0 +1,52 @@ +/** + * 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.broker.virtual; + +import java.net.URI; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.xbean.XBeanBrokerFactory; + +/** + * + * + */ +public class VirtualTopicPubSubUsingXBeanTest extends VirtualTopicPubSubTest { + + protected String getVirtualTopicConsumerName() { + return "VirtualTopicConsumers.ConsumerNumberOne.FOO"; + } + + protected String getVirtualTopicName() { + return "FOO"; + } + + protected BrokerService createBroker() throws Exception { + XBeanBrokerFactory factory = new XBeanBrokerFactory(); + BrokerService answer = factory.createBroker(new URI(getBrokerConfigUri())); + + // lets disable persistence as we are a test + answer.setPersistent(false); + + return answer; + } + + protected String getBrokerConfigUri() { + return "org/apache/activemq/broker/virtual/global-virtual-topics.xml"; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicSelectorTest.java new file mode 100644 index 0000000000..3287bab029 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicSelectorTest.java @@ -0,0 +1,105 @@ +/** + * 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.broker.virtual; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VirtualTopicSelectorTest extends CompositeTopicTest { + + private static final Logger LOG = LoggerFactory.getLogger(VirtualTopicSelectorTest.class); + + protected Destination getConsumer1Dsetination() { + return new ActiveMQQueue("Consumer.1.VirtualTopic.TEST"); + } + + protected Destination getConsumer2Dsetination() { + return new ActiveMQQueue("Consumer.2.VirtualTopic.TEST"); + } + + protected Destination getProducerDestination() { + return new ActiveMQTopic("VirtualTopic.TEST"); + } + + @Override + protected void assertMessagesArrived(ConsumerBean messageList1, ConsumerBean messageList2) { + messageList1.assertMessagesArrived(total/2); + messageList2.assertMessagesArrived(total/2); + + messageList1.flushMessages(); + messageList2.flushMessages(); + + LOG.info("validate no other messages on queues"); + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Destination destination1 = getConsumer1Dsetination(); + Destination destination2 = getConsumer2Dsetination(); + MessageConsumer c1 = session.createConsumer(destination1, null); + MessageConsumer c2 = session.createConsumer(destination2, null); + c1.setMessageListener(messageList1); + c2.setMessageListener(messageList2); + + + LOG.info("send one simple message that should go to both consumers"); + MessageProducer producer = session.createProducer(getProducerDestination()); + assertNotNull(producer); + + producer.send(session.createTextMessage("Last Message")); + + messageList1.assertMessagesArrived(1); + messageList2.assertMessagesArrived(1); + + } catch (JMSException e) { + e.printStackTrace(); + fail("unexpeced ex while waiting for last messages: " + e); + } + } + + @Override + protected BrokerService createBroker() throws Exception { + // use message selectors on consumers that need to propagate up to the virtual + // topic dispatch so that un matched messages do not linger on subscription queues + messageSelector1 = "odd = 'yes'"; + messageSelector2 = "odd = 'no'"; + + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + + VirtualTopic virtualTopic = new VirtualTopic(); + // the new config that enables selectors on the intercepter + virtualTopic.setSelectorAware(true); + VirtualDestinationInterceptor interceptor = new VirtualDestinationInterceptor(); + interceptor.setVirtualDestinations(new VirtualDestination[]{virtualTopic}); + broker.setDestinationInterceptors(new DestinationInterceptor[]{interceptor}); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicsAndDurableSubsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicsAndDurableSubsTest.java new file mode 100644 index 0000000000..d1e709f904 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/VirtualTopicsAndDurableSubsTest.java @@ -0,0 +1,103 @@ +/** + * 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.broker.virtual; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.broker.jmx.MBeanTest; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; + +public class VirtualTopicsAndDurableSubsTest extends MBeanTest { + + private Connection connection; + + public void testVirtualTopicCreationAndDurableSubs() throws Exception { + if (connection == null) { + connection = createConnection(); + } + connection.setClientID(getAClientID()); + connection.start(); + + ConsumerBean messageList = new ConsumerBean(); + messageList.setVerbose(true); + + String queueAName = getVirtualTopicConsumerName(); + // create consumer 'cluster' + ActiveMQQueue queue1 = new ActiveMQQueue(queueAName); + ActiveMQQueue queue2 = new ActiveMQQueue(queueAName); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer c1 = session.createConsumer(queue1); + MessageConsumer c2 = session.createConsumer(queue2); + + c1.setMessageListener(messageList); + c2.setMessageListener(messageList); + + // create topic producer + MessageProducer producer = session.createProducer(new ActiveMQTopic(getVirtualTopicName())); + assertNotNull(producer); + + int total = 10; + for (int i = 0; i < total; i++) { + producer.send(session.createTextMessage("message: " + i)); + } + messageList.assertMessagesArrived(total); + + //Add and remove durable subscriber after using VirtualTopics + assertCreateAndDestroyDurableSubscriptions(); + } + + protected String getAClientID(){ + return "VirtualTopicCreationAndDurableSubs"; + } + + protected String getVirtualTopicName() { + return "VirtualTopic.TEST"; + } + + + protected String getVirtualTopicConsumerName() { + return "Consumer.A.VirtualTopic.TEST"; + } + + protected String getDurableSubscriberName(){ + return "Sub1"; + } + + protected String getDurableSubscriberTopicName(){ + return "simple.topic"; + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + //Overrides test cases from MBeanTest to avoid having them run. + public void testMBeans() throws Exception {} + public void testMoveMessages() throws Exception {} + public void testRetryMessages() throws Exception {} + public void testMoveMessagesBySelector() throws Exception {} + public void testCopyMessagesBySelector() throws Exception {} +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/composite-queue.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/composite-queue.xml new file mode 100644 index 0000000000..ed3bc732a5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/composite-queue.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/composite-topic.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/composite-topic.xml new file mode 100644 index 0000000000..ded64719ef --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/composite-topic.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/disconnected-selector.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/disconnected-selector.xml new file mode 100644 index 0000000000..2772910d9a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/disconnected-selector.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/filtered-queue.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/filtered-queue.xml new file mode 100644 index 0000000000..d51f03ce64 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/filtered-queue.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/global-virtual-topics.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/global-virtual-topics.xml new file mode 100644 index 0000000000..ddd0667031 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/global-virtual-topics.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/virtual-individual-dlq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/virtual-individual-dlq.xml new file mode 100644 index 0000000000..d725436846 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/virtual-individual-dlq.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/virtual-topics-and-interceptor.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/virtual-topics-and-interceptor.xml new file mode 100644 index 0000000000..fcce72eb7a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/broker/virtual/virtual-topics-and-interceptor.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1282.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1282.java new file mode 100644 index 0000000000..9cd240f029 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1282.java @@ -0,0 +1,188 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * An AMQ-1282 Test + */ +public class AMQ1282 extends TestCase { + private ConnectionFactory factory; + private Connection connection; + private MapMessage message; + + @Override + protected void setUp() throws Exception { + factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + message = session.createMapMessage(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + connection.close(); + super.tearDown(); + } + + public void testUnmappedBooleanMessage() throws JMSException { + Object expected; + try { + expected = Boolean.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + Boolean actual = message.getBoolean("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + assertEquals(expected, ex); + } + } + + public void testUnmappedIntegerMessage() throws JMSException { + Object expected; + try { + expected = Integer.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + Integer actual = message.getInt("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + Class aClass = expected.getClass(); + assertTrue(aClass.isInstance(ex)); + } + } + + public void testUnmappedShortMessage() throws JMSException { + Object expected; + try { + expected = Short.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + Short actual = message.getShort("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + Class aClass = expected.getClass(); + assertTrue(aClass.isInstance(ex)); + } + } + + public void testUnmappedLongMessage() throws JMSException { + Object expected; + try { + expected = Long.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + Long actual = message.getLong("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + Class aClass = expected.getClass(); + assertTrue(aClass.isInstance(ex)); + } + } + + public void testUnmappedStringMessage() throws JMSException { + Object expected; + try { + expected = String.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + String actual = message.getString("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + Class aClass = expected.getClass(); + assertTrue(aClass.isInstance(ex)); + } + } + + public void testUnmappedCharMessage() throws JMSException { + try { + message.getChar("foo"); + fail("should have thrown NullPointerException"); + } catch (NullPointerException success) { + assertNotNull(success); + } + } + + public void testUnmappedByteMessage() throws JMSException { + Object expected; + try { + expected = Byte.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + Byte actual = message.getByte("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + Class aClass = expected.getClass(); + assertTrue(aClass.isInstance(ex)); + } + } + + public void testUnmappedDoubleMessage() throws JMSException { + Object expected; + try { + expected = Double.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + Double actual = message.getDouble("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + Class aClass = expected.getClass(); + assertTrue(aClass.isInstance(ex)); + } + } + + public void testUnmappedFloatMessage() throws JMSException { + Object expected; + try { + expected = Float.valueOf(null); + } catch (Exception ex) { + expected = ex; + } + try { + Float actual = message.getFloat("foo"); + assertEquals(expected, actual); + } catch (Exception ex) { + Class aClass = expected.getClass(); + assertTrue(aClass.isInstance(ex)); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1687Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1687Test.java new file mode 100644 index 0000000000..8e636d0024 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1687Test.java @@ -0,0 +1,104 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; + +/** + * + * + */ +public class AMQ1687Test extends EmbeddedBrokerTestSupport { + + private Connection connection; + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + //prefetch change is not required, but test will not fail w/o it, only spew errors in the AMQ log. + return new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getPublishableConnectString() +"?jms.prefetchPolicy.all=5"); + } + + public void testVirtualTopicCreation() throws Exception { + if (connection == null) { + connection = createConnection(); + } + connection.start(); + + ConsumerBean messageList = new ConsumerBean(); + messageList.setVerbose(true); + + String queueAName = getVirtualTopicConsumerName(); + String queueBName = getVirtualTopicConsumerNameB(); + + // create consumer 'cluster' + ActiveMQQueue queue1 = new ActiveMQQueue(queueAName); + ActiveMQQueue queue2 = new ActiveMQQueue(queueBName); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer c1 = session.createConsumer(queue1); + MessageConsumer c2 = session.createConsumer(queue2); + + c1.setMessageListener(messageList); + c2.setMessageListener(messageList); + + // create topic producer + ActiveMQTopic topic = new ActiveMQTopic(getVirtualTopicName()); + MessageProducer producer = session.createProducer(topic); + assertNotNull(producer); + + int total = 100; + for (int i = 0; i < total; i++) { + producer.send(session.createTextMessage("message: " + i)); + } + + messageList.assertMessagesArrived(total*2); + } + + protected String getVirtualTopicName() { + return "VirtualTopic.TEST"; + } + + protected String getVirtualTopicConsumerName() { + return "Consumer.A.VirtualTopic.TEST"; + } + + protected String getVirtualTopicConsumerNameB() { + return "Consumer.B.VirtualTopic.TEST"; + } + + protected void setUp() throws Exception { + this.bindAddress="tcp://localhost:0"; + super.setUp(); + } + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1853Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1853Test.java new file mode 100644 index 0000000000..a3c3b1d966 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1853Test.java @@ -0,0 +1,368 @@ +/** + * 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.bugs; + +import static org.junit.Assert.*; + +import java.net.URI; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQMessageProducer; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test validates that the AMQ consumer blocks on redelivery of a message, + * through all redeliveries, until the message is either successfully consumed + * or sent to the DLQ. + */ +public class AMQ1853Test { + private static BrokerService broker; + + private static final Logger LOG = LoggerFactory.getLogger(AMQ1853Test.class); + static final String jmsConnectionURI = "failover:(vm://localhost)"; + + // Virtual Topic that the test publishes 10 messages to + private static final String queueFail = "Queue.BlockingConsumer.QueueFail"; + + // Number of messages + + private final int producerMessages = 5; + private final int totalNumberMessages = producerMessages * 2; + private final int maxRedeliveries = 2; + private final int redeliveryDelay = 1000; + + private Map messageList = null; + + @Before + public void setUp() throws Exception { + broker = BrokerFactory.createBroker(new URI("broker:()/localhost?persistent=false")); + broker.setUseJmx(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + } + + @Test + public void testConsumerMessagesAreNotOrdered() throws Exception { + + TestConsumer consumerAllFail = null; + messageList = new Hashtable(); + + try { + + // The first 2 consumers will rollback, ultimately causing messages to land on the DLQ + + TestProducer producerAllFail = new TestProducer(queueFail); + thread(producerAllFail, false); + + consumerAllFail = new TestConsumer(queueFail, true); + thread(consumerAllFail, false); + + // Give the consumers a second to start + Thread.sleep(1000); + + thread(producerAllFail, false); + + // Give the consumers a second to start + Thread.sleep(1000); + + producerAllFail.getLatch().await(); + + LOG.info("producer successful, count = " + producerAllFail.getLatch().getCount()); + LOG.info("final message list size = " + messageList.size()); + + assertTrue("message list size = " + messageList.size() + " exptected:" + totalNumberMessages, + Wait.waitFor(new Condition() { + @Override + public boolean isSatisified() throws Exception { + return totalNumberMessages == messageList.size(); + } + })); + + consumerAllFail.getLatch().await(); + + LOG.info("consumerAllFail successful, count = " + consumerAllFail.getLatch().getCount()); + + Iterator keys = messageList.keySet().iterator(); + for (AtomicInteger counter : messageList.values()) { + String message = keys.next(); + LOG.info("final count for message " + message + " counter = " + counter.get()); + assertTrue("for message " + message + " counter = " + counter.get(), counter.get() == maxRedeliveries + 1); + } + + assertFalse(consumerAllFail.messageReceiptIsOrdered()); + } finally { + if (consumerAllFail != null) { + consumerAllFail.setStop(true); + } + } + } + + private static Thread thread(Runnable runnable, boolean daemon) { + Thread brokerThread = new Thread(runnable); + brokerThread.setDaemon(daemon); + brokerThread.start(); + return brokerThread; + } + + private class TestProducer implements Runnable { + + private CountDownLatch latch = null; + private String destinationName = null; + + public TestProducer(String destinationName) { + this.destinationName = destinationName; + // We run the producer 2 times + latch = new CountDownLatch(totalNumberMessages); + } + + public CountDownLatch getLatch() { + return latch; + } + + public void run() { + + ActiveMQConnectionFactory connectionFactory = null; + ActiveMQConnection connection = null; + ActiveMQSession session = null; + Destination destination = null; + + try { + LOG.info("Started TestProducer for destination (" + destinationName + ")"); + + connectionFactory = new ActiveMQConnectionFactory(jmsConnectionURI); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.setCopyMessageOnSend(false); + connection.start(); + session = (ActiveMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + destination = session.createQueue(this.destinationName); + + // Create a MessageProducer from the Session to the Topic or Queue + ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + for (int i = 0; i < (producerMessages); i++) { + TextMessage message = (TextMessage) session.createTextMessage(); + message.setLongProperty("TestTime", (System.currentTimeMillis())); + try { + producer.send(message); + LOG.info("Producer (" + destinationName + ")\n" + message.getJMSMessageID() + " = sent messageId\n"); + + latch.countDown(); + LOG.info(" Latch count " + latch.getCount()); + LOG.info("Producer message list size = " + messageList.keySet().size()); + messageList.put(message.getJMSMessageID(), new AtomicInteger(0)); + LOG.info("Producer message list size = " + messageList.keySet().size()); + + } catch (Exception deeperException) { + LOG.info("Producer for destination (" + destinationName + ") Caught: " + deeperException); + } + + Thread.sleep(1000); + } + + LOG.info("Finished TestProducer for destination (" + destinationName + ")"); + + } catch (Exception e) { + LOG.error("Terminating TestProducer(" + destinationName + ")Caught: " + e); + } finally { + try { + if (session != null) { + session.close(); + } + if (connection != null) { + connection.close(); + } + } catch (Exception e) { + LOG.error("Closing connection/session (" + destinationName + ")Caught: " + e); + } + } + } + } + + private class TestConsumer implements Runnable, ExceptionListener, MessageListener { + + private CountDownLatch latch = null; + private int receivedMessageCounter = 0; + private boolean bFakeFail = false; + String destinationName = null; + boolean bMessageReceiptIsOrdered = true; + boolean bStop = false; + String previousMessageId = null; + + private ActiveMQConnectionFactory connectionFactory = null; + private ActiveMQConnection connection = null; + private Session session = null; + private MessageConsumer consumer = null; + + public TestConsumer(String destinationName, boolean bFakeFail) { + this.bFakeFail = bFakeFail; + latch = new CountDownLatch(totalNumberMessages * (this.bFakeFail ? (maxRedeliveries + 1) : 1)); + this.destinationName = destinationName; + } + + public CountDownLatch getLatch() { + return latch; + } + + public boolean messageReceiptIsOrdered() { + return bMessageReceiptIsOrdered; + } + + public void run() { + + try { + LOG.info("Started TestConsumer for destination (" + destinationName + ")"); + + connectionFactory = new ActiveMQConnectionFactory(jmsConnectionURI); + connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.setNonBlockingRedelivery(true); + session = connection.createSession(true, Session.SESSION_TRANSACTED); + + RedeliveryPolicy policy = connection.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(redeliveryDelay); + policy.setBackOffMultiplier(-1); + policy.setRedeliveryDelay(redeliveryDelay); + policy.setMaximumRedeliveryDelay(-1); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(maxRedeliveries); + + connection.setExceptionListener(this); + Destination destination = session.createQueue(destinationName); + consumer = session.createConsumer(destination); + consumer.setMessageListener(this); + + connection.start(); + + while (!bStop) { + Thread.sleep(100); + } + + LOG.info("Finished TestConsumer for destination name (" + destinationName + ") remaining " + this.latch.getCount() + + " messages " + this.toString()); + + } catch (Exception e) { + LOG.error("Consumer (" + destinationName + ") Caught: " + e); + } finally { + try { + if (consumer != null) { + consumer.close(); + } + if (session != null) { + session.close(); + } + if (connection != null) { + connection.close(); + } + } catch (Exception e) { + LOG.error("Closing connection/session (" + destinationName + ")Caught: " + e); + } + } + } + + public synchronized void onException(JMSException ex) { + LOG.error("Consumer for destination, (" + destinationName + "), JMS Exception occured. Shutting down client."); + } + + public synchronized void setStop(boolean bStop) { + this.bStop = bStop; + } + + public synchronized void onMessage(Message message) { + receivedMessageCounter++; + latch.countDown(); + + LOG.info("Consumer for destination (" + destinationName + ") latch countdown: " + latch.getCount() + + " :: Number messages received " + this.receivedMessageCounter); + + try { + + if (receivedMessageCounter % (maxRedeliveries + 1) == 1) { + previousMessageId = message.getJMSMessageID(); + } + + if (bMessageReceiptIsOrdered) { + bMessageReceiptIsOrdered = previousMessageId.trim().equals(message.getJMSMessageID()); + } + + final String jmsMessageId = message.getJMSMessageID(); + assertTrue("Did not find expected ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return messageList.containsKey(jmsMessageId); + } + })); + + AtomicInteger counter = messageList.get(jmsMessageId); + counter.incrementAndGet(); + + LOG.info("Consumer for destination (" + destinationName + ")\n" + message.getJMSMessageID() + " = currentMessageId\n" + + previousMessageId + " = previousMessageId\n" + bMessageReceiptIsOrdered + "= bMessageReceiptIsOrdered\n" + + ">>LATENCY " + (System.currentTimeMillis() - message.getLongProperty("TestTime")) + "\n" + "message counter = " + + counter.get()); + + if (!bFakeFail) { + LOG.debug("Consumer on destination " + destinationName + " committing JMS Session for message: " + message.toString()); + session.commit(); + } else { + LOG.debug("Consumer on destination " + destinationName + " rolling back JMS Session for message: " + message.toString()); + session.rollback(); // rolls back all the consumed messages on the session to + } + + } catch (Exception ex) { + ex.printStackTrace(); + LOG.error("Error reading JMS Message from destination " + destinationName + "."); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1866.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1866.java new file mode 100644 index 0000000000..1bdd72e6af --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1866.java @@ -0,0 +1,224 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.leveldb.LevelDBStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a test case for the issue reported at: + * https://issues.apache.org/activemq/browse/AMQ-1866 + * + * If you have a JMS producer sending messages to multiple fast consumers and + * one slow consumer, eventually all consumers will run as slow as + * the slowest consumer. + */ +public class AMQ1866 extends TestCase { + + private static final Logger log = LoggerFactory.getLogger(ConsumerThread.class); + private BrokerService brokerService; + private ArrayList threads = new ArrayList(); + + private final String ACTIVEMQ_BROKER_BIND = "tcp://localhost:0"; + private String ACTIVEMQ_BROKER_URI; + + AtomicBoolean shutdown = new AtomicBoolean(); + private ActiveMQQueue destination; + + @Override + protected void setUp() throws Exception { + // Start an embedded broker up. + brokerService = new BrokerService(); + LevelDBStore adaptor = new LevelDBStore(); + brokerService.setPersistenceAdapter(adaptor); + brokerService.deleteAllMessages(); + + // A small max page size makes this issue occur faster. + PolicyMap policyMap = new PolicyMap(); + PolicyEntry pe = new PolicyEntry(); + pe.setMaxPageSize(1); + policyMap.put(new ActiveMQQueue(">"), pe); + brokerService.setDestinationPolicy(policyMap); + + brokerService.addConnector(ACTIVEMQ_BROKER_BIND); + brokerService.start(); + + ACTIVEMQ_BROKER_URI = brokerService.getTransportConnectors().get(0).getPublishableConnectString(); + destination = new ActiveMQQueue(getName()); + } + + @Override + protected void tearDown() throws Exception { + // Stop any running threads. + shutdown.set(true); + for (Thread t : threads) { + t.interrupt(); + t.join(); + } + brokerService.stop(); + } + + public void testConsumerSlowDownPrefetch0() throws Exception { + ACTIVEMQ_BROKER_URI = ACTIVEMQ_BROKER_URI + "?jms.prefetchPolicy.queuePrefetch=0"; + doTestConsumerSlowDown(); + } + + public void testConsumerSlowDownPrefetch10() throws Exception { + ACTIVEMQ_BROKER_URI = ACTIVEMQ_BROKER_URI + "?jms.prefetchPolicy.queuePrefetch=10"; + doTestConsumerSlowDown(); + } + + public void testConsumerSlowDownDefaultPrefetch() throws Exception { + doTestConsumerSlowDown(); + } + + public void doTestConsumerSlowDown() throws Exception { + + // Preload the queue. + produce(20000); + + Thread producer = new Thread() { + @Override + public void run() { + try { + while(!shutdown.get()) { + produce(1000); + } + } catch (Exception e) { + } + } + }; + threads.add(producer); + producer.start(); + + // This is the slow consumer. + ConsumerThread c1 = new ConsumerThread("Consumer-1"); + threads.add(c1); + c1.start(); + + // Wait a bit so that the slow consumer gets assigned most of the messages. + Thread.sleep(500); + ConsumerThread c2 = new ConsumerThread("Consumer-2"); + threads.add(c2); + c2.start(); + + int totalReceived = 0; + for ( int i=0; i < 30; i++) { + Thread.sleep(1000); + long c1Counter = c1.counter.getAndSet(0); + long c2Counter = c2.counter.getAndSet(0); + log.debug("c1: "+c1Counter+", c2: "+c2Counter); + totalReceived += c1Counter; + totalReceived += c2Counter; + + // Once message have been flowing for a few seconds, start asserting that c2 always gets messages. It should be receiving about 100 / sec + if( i > 10 ) { + assertTrue("Total received=" + totalReceived + ", Consumer 2 should be receiving new messages every second.", c2Counter > 0); + } + } + } + + public void produce(int count) throws Exception { + Connection connection=null; + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(ACTIVEMQ_BROKER_URI); + factory.setDispatchAsync(true); + + connection = factory.createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + connection.start(); + + for( int i=0 ; i< count; i++ ) { + producer.send(session.createTextMessage(getName()+" Message "+(++i))); + } + + } finally { + try { + connection.close(); + } catch (Throwable e) { + } + } + } + + public class ConsumerThread extends Thread { + final AtomicLong counter = new AtomicLong(); + + public ConsumerThread(String threadId) { + super(threadId); + } + + public void run() { + Connection connection=null; + try { + log.debug(getName() + ": is running"); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(ACTIVEMQ_BROKER_URI); + factory.setDispatchAsync(true); + + connection = factory.createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + + while (!shutdown.get()) { + TextMessage msg = (TextMessage)consumer.receive(1000); + if ( msg!=null ) { + int sleepingTime; + if (getName().equals("Consumer-1")) { + sleepingTime = 1000 * 1000; + } else { + sleepingTime = 1; + } + counter.incrementAndGet(); + Thread.sleep(sleepingTime); + } + } + + } catch (Exception e) { + } finally { + log.debug(getName() + ": is stopping"); + try { + connection.close(); + } catch (Throwable e) { + } + } + } + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1893Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1893Test.java new file mode 100644 index 0000000000..f5ccd50269 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1893Test.java @@ -0,0 +1,196 @@ +/** + * 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.bugs; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class AMQ1893Test extends TestCase { + + private static final Logger log = LoggerFactory.getLogger(AMQ1893Test.class); + + static final String QUEUE_NAME = "TEST"; + + static final int MESSAGE_COUNT_OF_ONE_GROUP = 10000; + + static final int[] PRIORITIES = new int[]{0, 5, 10}; + + static final boolean debug = false; + + private BrokerService brokerService; + + private ActiveMQQueue destination; + + @Override + protected void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.addConnector("tcp://localhost:0"); + brokerService.start(); + destination = new ActiveMQQueue(QUEUE_NAME); + } + + @Override + protected void tearDown() throws Exception { + // Stop any running threads. + brokerService.stop(); + } + + + public void testProduceConsumeWithSelector() throws Exception { + new TestProducer().produceMessages(); + new TestConsumer().consume(); + } + + + class TestProducer { + + public void produceMessages() throws Exception { + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( + brokerService.getTransportConnectors().get(0).getConnectUri().toString() + ); + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(QUEUE_NAME); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + long start = System.currentTimeMillis(); + + for (int priority : PRIORITIES) { + + String name = null; + if (priority == 10) { + name = "high"; + } else if (priority == 5) { + name = "mid"; + } else { + name = "low"; + } + + for (int i = 1; i <= MESSAGE_COUNT_OF_ONE_GROUP; i++) { + + TextMessage message = session.createTextMessage(name + "_" + i); + message.setIntProperty("priority", priority); + + producer.send(message); + } + } + + long end = System.currentTimeMillis(); + + log.info("sent " + (MESSAGE_COUNT_OF_ONE_GROUP * 3) + " messages in " + (end - start) + " ms"); + + producer.close(); + session.close(); + connection.close(); + } + } + + class TestConsumer { + + private CountDownLatch finishLatch = new CountDownLatch(1); + + + + public void consume() throws Exception { + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( + brokerService.getTransportConnectors().get(0).getConnectUri().toString() + ); + + + final int totalMessageCount = MESSAGE_COUNT_OF_ONE_GROUP * PRIORITIES.length; + final AtomicInteger counter = new AtomicInteger(); + final MessageListener listener = new MessageListener() { + public void onMessage(Message message) { + + if (debug) { + try { + log.info(((TextMessage) message).getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + } + + if (counter.incrementAndGet() == totalMessageCount) { + + finishLatch.countDown(); + + } + } + }; + + int consumerCount = PRIORITIES.length; + Connection[] connections = new Connection[consumerCount]; + Session[] sessions = new Session[consumerCount]; + MessageConsumer[] consumers = new MessageConsumer[consumerCount]; + + for (int i = 0; i < consumerCount; i++) { + String selector = "priority = " + PRIORITIES[i]; + + connections[i] = connectionFactory.createConnection(); + sessions[i] = connections[i].createSession(false, Session.AUTO_ACKNOWLEDGE); + + consumers[i] = sessions[i].createConsumer(destination, selector); + consumers[i].setMessageListener(listener); + } + + for (Connection connection : connections) { + connection.start(); + } + + log.info("received " + counter.get() + " messages"); + + assertTrue("got all messages in time", finishLatch.await(60, TimeUnit.SECONDS)); + + log.info("received " + counter.get() + " messages"); + + for (MessageConsumer consumer : consumers) { + consumer.close(); + } + + for (Session session : sessions) { + session.close(); + } + + for (Connection connection : connections) { + connection.close(); + } + } + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1917Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1917Test.java new file mode 100644 index 0000000000..f896342dcc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1917Test.java @@ -0,0 +1,228 @@ +/** + * 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.bugs; + +import junit.framework.TestCase; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; + + +public class AMQ1917Test extends TestCase { + + private static final int NUM_MESSAGES = 4000; + private static final int NUM_THREADS = 10; + private static final String REQUEST_QUEUE = "mock.in.queue"; + private static final String REPLY_QUEUE = "mock.out.queue"; + + private Destination requestDestination = ActiveMQDestination.createDestination( + REQUEST_QUEUE, ActiveMQDestination.QUEUE_TYPE); + private Destination replyDestination = ActiveMQDestination.createDestination( + REPLY_QUEUE, ActiveMQDestination.QUEUE_TYPE); + + private CountDownLatch roundTripLatch = new CountDownLatch(NUM_MESSAGES); + private CountDownLatch errorLatch = new CountDownLatch(1); + private ThreadPoolExecutor tpe; + private final String BROKER_URL = "tcp://localhost:0"; + private String connectionUri; + private BrokerService broker = null; + private boolean working = true; + + // trival session/producer pool + final Session[] sessions = new Session[NUM_THREADS]; + final MessageProducer[] producers = new MessageProducer[NUM_THREADS]; + + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.addConnector(BROKER_URL); + broker.start(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + + BlockingQueue queue = new ArrayBlockingQueue(10000); + tpe = new ThreadPoolExecutor(NUM_THREADS, NUM_THREADS, 60000, + TimeUnit.MILLISECONDS, queue); + ThreadFactory limitedthreadFactory = new LimitedThreadFactory(tpe.getThreadFactory()); + tpe.setThreadFactory(limitedthreadFactory); + } + + public void tearDown() throws Exception { + broker.stop(); + tpe.shutdown(); + } + + public void testLoadedSendRecieveWithCorrelationId() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new org.apache.activemq.ActiveMQConnectionFactory(); + connectionFactory.setBrokerURL(connectionUri); + Connection connection = connectionFactory.createConnection(); + setupReceiver(connection); + + connection = connectionFactory.createConnection(); + connection.start(); + + // trival session/producer pool + for (int i=0; i NUM_THREADS) { + errorLatch.countDown(); + fail("too many threads requested"); + } + return factory.newThread(arg0); + } + } + } + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1936Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1936Test.java new file mode 100644 index 0000000000..2c865621fa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ1936Test.java @@ -0,0 +1,310 @@ +/** + * 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.bugs; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueReceiver; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.jms.TextMessage; +import javax.naming.NamingException; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.AutoFailTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; +import org.apache.log4j.Logger; + +/** + * A AMQ1936Test + * + */ +public class AMQ1936Test extends TestCase { + private final static Logger logger = Logger.getLogger(AMQ1936Test.class); + private final static String TEST_QUEUE_NAME = "dynamicQueues/duplicate.message.test.queue"; + // //-- + // + private final static long TEST_MESSAGE_COUNT = 6000; // The number of test messages to use + // + // //-- + private final static int CONSUMER_COUNT = 2; // The number of message receiver instances + private final static boolean TRANSACTED_RECEIVE = true; // Flag used by receiver which indicates messages should be + // processed within a JMS transaction + + private final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CONSUMER_COUNT, CONSUMER_COUNT, Long.MAX_VALUE, TimeUnit.SECONDS, + new LinkedBlockingQueue()); + private final ThreadedMessageReceiver[] receivers = new ThreadedMessageReceiver[CONSUMER_COUNT]; + private BrokerService broker = null; + static QueueConnectionFactory connectionFactory = null; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + broker = new BrokerService(); + broker.getSystemUsage().getMemoryUsage().setLimit(5 * 1024 * 1024); + broker.setBrokerName("test"); + broker.setDeleteAllMessagesOnStartup(true); + broker.start(); + connectionFactory = new ActiveMQConnectionFactory("vm://test"); + ; + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + if (threadPool != null) { + // signal receivers to stop + for (ThreadedMessageReceiver receiver : receivers) { + receiver.setShouldStop(true); + } + + logger.info("Waiting for receivers to shutdown.."); + if (!threadPool.awaitTermination(10, TimeUnit.SECONDS)) { + logger.warn("Not all receivers completed shutdown."); + } else { + logger.info("All receivers shutdown successfully.."); + } + } + + logger.debug("Stoping the broker."); + + if (broker != null) { + broker.stop(); + } + } + + private void sendTextMessage(String queueName, int i) throws JMSException, NamingException { + QueueConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://test"); + QueueConnection queueConnection = null; + QueueSession session = null; + QueueSender sender = null; + Queue queue = null; + TextMessage message = null; + + try { + + // Create the queue connection + queueConnection = connectionFactory.createQueueConnection(); + + session = queueConnection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE); + queue = session.createQueue(TEST_QUEUE_NAME); + sender = session.createSender(queue); + sender.setDeliveryMode(DeliveryMode.PERSISTENT); + + message = session.createTextMessage(String.valueOf(i)); + + // send the message + sender.send(message); + + if (session.getTransacted()) { + session.commit(); + } + if (i % 1000 == 0) { + logger.info("Message successfully sent to : " + queue.getQueueName() + " messageid: " + message.getJMSMessageID() + " content:" + + message.getText()); + } + } finally { + if (sender != null) { + sender.close(); + } + if (session != null) { + session.close(); + } + if (queueConnection != null) { + queueConnection.close(); + } + } + } + + public void testForDuplicateMessages() throws Exception { + final ConcurrentHashMap messages = new ConcurrentHashMap(); + final Object lock = new Object(); + final CountDownLatch duplicateSignal = new CountDownLatch(1); + final AtomicInteger messageCount = new AtomicInteger(0); + + // add 1/2 the number of our total messages + for (int i = 0; i < TEST_MESSAGE_COUNT / 2; i++) { + if (duplicateSignal.getCount() == 0) { + fail("Duplicate message id detected"); + } + sendTextMessage(TEST_QUEUE_NAME, i); + } + + // create a number of consumers to read of the messages and start them with a handler which simply stores the + // message ids + // in a Map and checks for a duplicate + for (int i = 0; i < CONSUMER_COUNT; i++) { + receivers[i] = new ThreadedMessageReceiver(TEST_QUEUE_NAME, new IMessageHandler() { + + @Override + public void onMessage(Message message) throws Exception { + synchronized (lock) { + int current = messageCount.incrementAndGet(); + if (current % 1000 == 0) { + logger.info("Received message:" + message.getJMSMessageID() + " with content: " + ((TextMessage) message).getText()); + } + if (messages.containsKey(message.getJMSMessageID())) { + duplicateSignal.countDown(); + logger.fatal("duplicate message id detected:" + message.getJMSMessageID()); + fail("Duplicate message id detected:" + message.getJMSMessageID()); + } else { + messages.put(message.getJMSMessageID(), message.getJMSMessageID()); + } + } + } + }); + threadPool.submit(receivers[i]); + } + + // starting adding the remaining messages + for (int i = 0; i < TEST_MESSAGE_COUNT / 2; i++) { + if (duplicateSignal.getCount() == 0) { + fail("Duplicate message id detected"); + } + sendTextMessage(TEST_QUEUE_NAME, i); + } + + logger.info("sent all " + TEST_MESSAGE_COUNT + " messages"); + + // allow some time for messages to be delivered to receivers. + boolean ok = Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return TEST_MESSAGE_COUNT == messages.size(); + } + }, TimeUnit.MINUTES.toMillis(7)); + if (!ok) { + AutoFailTestSupport.dumpAllThreads("--STUCK?--"); + } + assertEquals("Number of messages received does not match the number sent", TEST_MESSAGE_COUNT, messages.size()); + assertEquals(TEST_MESSAGE_COUNT, messageCount.get()); + } + + private final static class ThreadedMessageReceiver implements Runnable { + + private IMessageHandler handler = null; + private final AtomicBoolean shouldStop = new AtomicBoolean(false); + + public ThreadedMessageReceiver(String queueName, IMessageHandler handler) { + this.handler = handler; + } + + @Override + public void run() { + + QueueConnection queueConnection = null; + QueueSession session = null; + QueueReceiver receiver = null; + Queue queue = null; + Message message = null; + try { + try { + + queueConnection = connectionFactory.createQueueConnection(); + // create a transacted session + session = queueConnection.createQueueSession(TRANSACTED_RECEIVE, QueueSession.AUTO_ACKNOWLEDGE); + queue = session.createQueue(TEST_QUEUE_NAME); + receiver = session.createReceiver(queue); + + // start the connection + queueConnection.start(); + + logger.info("Receiver " + Thread.currentThread().getName() + " connected."); + + // start receive loop + while (!(shouldStop.get() || Thread.currentThread().isInterrupted())) { + try { + message = receiver.receive(200); + } catch (Exception e) { + // + // ignore interrupted exceptions + // + if (e instanceof InterruptedException || e.getCause() instanceof InterruptedException) { + /* ignore */ + } else { + throw e; + } + } + + if (message != null && this.handler != null) { + this.handler.onMessage(message); + } + + // commit session on successful handling of message + if (session.getTransacted()) { + session.commit(); + } + } + + logger.info("Receiver " + Thread.currentThread().getName() + " shutting down."); + + } finally { + if (receiver != null) { + try { + receiver.close(); + } catch (JMSException e) { + logger.warn(e); + } + } + if (session != null) { + try { + session.close(); + } catch (JMSException e) { + logger.warn(e); + } + } + if (queueConnection != null) { + queueConnection.close(); + } + } + } catch (JMSException e) { + logger.error(e); + e.printStackTrace(); + } catch (NamingException e) { + logger.error(e); + } catch (Exception e) { + logger.error(e); + e.printStackTrace(); + } + } + + public void setShouldStop(Boolean shouldStop) { + this.shouldStop.set(shouldStop); + } + } + + public interface IMessageHandler { + void onMessage(Message message) throws Exception; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2021Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2021Test.java new file mode 100644 index 0000000000..9abab3f607 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2021Test.java @@ -0,0 +1,267 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.ArrayList; +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a test case for the issue reported at: https://issues.apache.org/activemq/browse/AMQ-2021 Bug is modification + * of inflight message properties so the failure can manifest itself in a bunch or ways, from message receipt with null + * properties to marshall errors + */ +public class AMQ2021Test implements ExceptionListener, UncaughtExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(AMQ2021Test.class); + BrokerService brokerService; + ArrayList threads = new ArrayList(); + Vector exceptions; + + @Rule + public TestName name = new TestName(); + + AMQ2021Test testCase; + + private final String ACTIVEMQ_BROKER_BIND = "tcp://localhost:0"; + private String CONSUMER_BROKER_URL = "?jms.redeliveryPolicy.maximumRedeliveries=1&jms.redeliveryPolicy.initialRedeliveryDelay=0"; + private String PRODUCER_BROKER_URL; + + private final int numMessages = 1000; + private final int numConsumers = 2; + private final int dlqMessages = numMessages / 2; + + private CountDownLatch receivedLatch; + private ActiveMQTopic destination; + private CountDownLatch started; + + @Before + public void setUp() throws Exception { + Thread.setDefaultUncaughtExceptionHandler(this); + testCase = this; + + // Start an embedded broker up. + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.addConnector(ACTIVEMQ_BROKER_BIND); + brokerService.start(); + destination = new ActiveMQTopic(name.getMethodName()); + exceptions = new Vector(); + + CONSUMER_BROKER_URL = brokerService.getTransportConnectors().get(0).getPublishableConnectString() + CONSUMER_BROKER_URL; + PRODUCER_BROKER_URL = brokerService.getTransportConnectors().get(0).getPublishableConnectString(); + + receivedLatch = new CountDownLatch(numConsumers * (numMessages + dlqMessages)); + started = new CountDownLatch(1); + } + + @After + public void tearDown() throws Exception { + for (Thread t : threads) { + t.interrupt(); + t.join(); + } + brokerService.stop(); + } + + @Test(timeout=240000) + public void testConcurrentTopicResendToDLQ() throws Exception { + + for (int i = 0; i < numConsumers; i++) { + ConsumerThread c1 = new ConsumerThread("Consumer-" + i); + threads.add(c1); + c1.start(); + } + + assertTrue(started.await(10, TimeUnit.SECONDS)); + + Thread producer = new Thread() { + @Override + public void run() { + try { + produce(numMessages); + } catch (Exception e) { + } + } + }; + threads.add(producer); + producer.start(); + + boolean allGood = receivedLatch.await(90, TimeUnit.SECONDS); + for (Throwable t : exceptions) { + log.error("failing test with first exception", t); + fail("exception during test : " + t); + } + assertTrue("excepted messages received within time limit", allGood); + + assertEquals(0, exceptions.size()); + + for (int i = 0; i < numConsumers; i++) { + // last recovery sends message to deq so is not received again + assertEquals(dlqMessages * 2, ((ConsumerThread) threads.get(i)).recoveries); + assertEquals(numMessages + dlqMessages, ((ConsumerThread) threads.get(i)).counter); + } + + // half of the messages for each consumer should go to the dlq but duplicates will + // be suppressed + consumeFromDLQ(dlqMessages); + + } + + private void consumeFromDLQ(int messageCount) throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(CONSUMER_BROKER_URL); + Connection connection = connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer dlqConsumer = session.createConsumer(new ActiveMQQueue("ActiveMQ.DLQ")); + int count = 0; + for (int i = 0; i < messageCount; i++) { + if (dlqConsumer.receive(1000) == null) { + break; + } + count++; + } + assertEquals(messageCount, count); + } + + public void produce(int count) throws Exception { + Connection connection = null; + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(PRODUCER_BROKER_URL); + connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(0); + connection.start(); + + for (int i = 0; i < count; i++) { + int id = i + 1; + TextMessage message = session.createTextMessage(name.getMethodName() + " Message " + id); + message.setIntProperty("MsgNumber", id); + producer.send(message); + + if (id % 500 == 0) { + log.info("sent " + id + ", ith " + message); + } + } + } catch (JMSException e) { + log.error("unexpected ex on produce", e); + exceptions.add(e); + } finally { + try { + if (connection != null) { + connection.close(); + } + } catch (Throwable e) { + } + } + } + + public class ConsumerThread extends Thread implements MessageListener { + public long counter = 0; + public long recoveries = 0; + private Session session; + + public ConsumerThread(String threadId) { + super(threadId); + } + + @Override + public void run() { + try { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(CONSUMER_BROKER_URL); + Connection connection = connectionFactory.createConnection(); + connection.setExceptionListener(testCase); + connection.setClientID(getName()); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(destination, getName()); + consumer.setMessageListener(this); + connection.start(); + + started.countDown(); + + } catch (JMSException exception) { + log.error("unexpected ex in consumer run", exception); + exceptions.add(exception); + } + } + + @Override + public void onMessage(Message message) { + try { + counter++; + int messageNumber = message.getIntProperty("MsgNumber"); + if (messageNumber % 2 == 0) { + session.recover(); + recoveries++; + } else { + message.acknowledge(); + } + + if (counter % 200 == 0) { + log.info("recoveries:" + recoveries + ", Received " + counter + ", counter'th " + message); + } + receivedLatch.countDown(); + } catch (Exception e) { + log.error("unexpected ex on onMessage", e); + exceptions.add(e); + } + } + + } + + @Override + public void onException(JMSException exception) { + log.info("Unexpected JMSException", exception); + exceptions.add(exception); + } + + @Override + public void uncaughtException(Thread thread, Throwable exception) { + log.info("Unexpected exception from thread " + thread + ", ex: " + exception); + exceptions.add(exception); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2084Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2084Test.java new file mode 100644 index 0000000000..1f31864a15 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2084Test.java @@ -0,0 +1,181 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueReceiver; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import javax.naming.InitialContext; + +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2084Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2084Test.class); + BrokerService broker; + CountDownLatch qreceived; + String connectionUri; + + @Before + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString(); + broker.start(); + + qreceived = new CountDownLatch(1); + } + + @After + public void stopBroker() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + public void listenQueue(final String queueName, final String selectors) { + try { + Properties props = new Properties(); + props.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + props.put("java.naming.provider.url", connectionUri); + props.put("queue.queueName", queueName); + + javax.naming.Context ctx = new InitialContext(props); + QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory"); + QueueConnection conn = factory.createQueueConnection(); + final Queue queue = (Queue) ctx.lookup("queueName"); + QueueSession session = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + QueueReceiver receiver = session.createReceiver(queue, selectors); + System.out.println("Message Selector: " + receiver.getMessageSelector()); + receiver.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage txtMsg = (TextMessage) message; + String msg = txtMsg.getText(); + LOG.info("Queue Message Received: " + queueName + " - " + msg); + qreceived.countDown(); + + } + message.acknowledge(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); + conn.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void listenTopic(final String topicName, final String selectors) { + try { + Properties props = new Properties(); + props.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + props.put("java.naming.provider.url", connectionUri); + props.put("topic.topicName", topicName); + + javax.naming.Context ctx = new InitialContext(props); + TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("ConnectionFactory"); + TopicConnection conn = factory.createTopicConnection(); + final Topic topic = (Topic) ctx.lookup("topicName"); + TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber receiver = session.createSubscriber(topic, selectors, false); + + receiver.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + TextMessage txtMsg = (TextMessage) message; + String msg = txtMsg.getText(); + LOG.info("Topic Message Received: " + topicName + " - " + msg); + } + message.acknowledge(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + conn.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void publish(String topicName, String message) { + try { + Properties props = new Properties(); + props.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + props.put("java.naming.provider.url", connectionUri); + props.put("topic.topicName", topicName); + javax.naming.Context ctx = new InitialContext(props); + TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("ConnectionFactory"); + TopicConnection conn = factory.createTopicConnection(); + Topic topic = (Topic) ctx.lookup("topicName"); + TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = session.createPublisher(topic); + if (message != null) { + Message msg = session.createTextMessage(message); + publisher.send(msg); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void tryXpathSelectorMatch() throws Exception { + String xPath = "XPATH '//books//book[@lang=''en'']'"; + listenQueue("Consumer.Sample.VirtualTopic.TestXpath", xPath); + publish("VirtualTopic.TestXpath", "ABC"); + assertTrue("topic received: ", qreceived.await(20, TimeUnit.SECONDS)); + } + + @Test + public void tryXpathSelectorNoMatch() throws Exception { + String xPath = "XPATH '//books//book[@lang=''es'']'"; + listenQueue("Consumer.Sample.VirtualTopic.TestXpath", xPath); + publish("VirtualTopic.TestXpath", "ABC"); + assertFalse("topic did not receive unmatched", qreceived.await(5, TimeUnit.SECONDS)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2103Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2103Test.java new file mode 100644 index 0000000000..8a952fd699 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2103Test.java @@ -0,0 +1,129 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.broker.BrokerTestSupport; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMapMessage; +import org.apache.activemq.command.ActiveMQObjectMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.usecases.MyObject; + +public class AMQ2103Test extends BrokerTestSupport { + static PolicyEntry reduceMemoryFootprint = new PolicyEntry(); + static { + reduceMemoryFootprint.setReduceMemoryFootprint(true); + } + + public PolicyEntry defaultPolicy = reduceMemoryFootprint; + + @Override + protected PolicyEntry getDefaultPolicy() { + return defaultPolicy; + } + + public void initCombosForTestVerifyMarshalledStateIsCleared() throws Exception { + addCombinationValues("defaultPolicy", new Object[]{defaultPolicy, null}); + } + + public static Test suite() { + return suite(AMQ2103Test.class); + } + + /** + * use mem persistence so no marshaling, + * reduceMemoryFootprint on/off that will reduce memory by whacking the marshaled state + * With vm transport and deferred serialisation and no persistence (mem persistence), + * we see the message as sent by the client so we can validate the contents against + * the policy + * @throws Exception + */ + public void testVerifyMarshalledStateIsCleared() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setOptimizedMessageDispatch(true); + factory.setObjectMessageSerializationDefered(true); + factory.setCopyMessageOnSend(false); + + Connection connection = factory.createConnection(); + Session session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQDestination destination = new ActiveMQQueue("testQ"); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + + MessageProducer producer = session.createProducer(destination); + final MyObject obj = new MyObject("A message"); + ActiveMQObjectMessage m1 = (ActiveMQObjectMessage)session.createObjectMessage(); + m1.setObject(obj); + producer.send(m1); + + ActiveMQTextMessage m2 = new ActiveMQTextMessage(); + m2.setText("Test Message Payload."); + producer.send(m2); + + ActiveMQMapMessage m3 = new ActiveMQMapMessage(); + m3.setString("text", "my message"); + producer.send(m3); + + Message m = consumer.receive(maxWait); + assertNotNull(m); + assertEquals(m1.getMessageId().toString(), m.getJMSMessageID()); + assertTrue(m instanceof ActiveMQObjectMessage); + + if (getDefaultPolicy() != null) { + assertNull("object data cleared by reduceMemoryFootprint (and never marshalled as using mem persistence)", + ((ActiveMQObjectMessage)m).getObject()); + } + + // verify no serialisation via vm transport + assertEquals("writeObject called", 0, obj.getWriteObjectCalled()); + assertEquals("readObject called", 0, obj.getReadObjectCalled()); + assertEquals("readObjectNoData called", 0, obj.getReadObjectNoDataCalled()); + + m = consumer.receive(maxWait); + assertNotNull(m); + assertEquals(m2.getMessageId().toString(), m.getJMSMessageID()); + assertTrue(m instanceof ActiveMQTextMessage); + + if (getDefaultPolicy() != null) { + assertNull("text cleared by reduceMemoryFootprint (and never marshalled as using mem persistence)", + ((ActiveMQTextMessage)m).getText()); + } + + m = consumer.receive(maxWait); + assertNotNull(m); + assertEquals(m3.getMessageId().toString(), m.getJMSMessageID()); + assertTrue(m instanceof ActiveMQMapMessage); + + if (getDefaultPolicy() != null) { + assertNull("text cleared by reduceMemoryFootprint (and never marshalled as using mem persistence)", + ((ActiveMQMapMessage)m).getStringProperty("text")); + } + + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2149LevelDBTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2149LevelDBTest.java new file mode 100644 index 0000000000..1ad8b68991 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2149LevelDBTest.java @@ -0,0 +1,30 @@ +/** + * 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.bugs; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; + +public class AMQ2149LevelDBTest extends AMQ2149Test { + + @Override + protected void configurePersistenceAdapter(BrokerService brokerService) throws Exception { + LevelDBStore persistenceFactory = new LevelDBStore(); + persistenceFactory.setDirectory(dataDirFile); + brokerService.setPersistenceAdapter(persistenceFactory); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2149Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2149Test.java new file mode 100644 index 0000000000..b2eba61366 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2149Test.java @@ -0,0 +1,584 @@ +/** + * 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.bugs; + +import java.io.File; +import java.lang.IllegalStateException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Vector; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.jms.*; + +import org.apache.activemq.AutoFailTestSupport; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.util.LoggingBrokerPlugin; +import org.apache.activemq.command.ActiveMQDestination; +import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.*; + +interface Configurer { + public void configure(BrokerService broker) throws Exception; +} + +public class AMQ2149Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2149Test.class); + @Rule + public TestName testName = new TestName(); + + private static final String BROKER_CONNECTOR = "tcp://localhost:61617"; + private static final String DEFAULT_BROKER_URL = "failover:("+ BROKER_CONNECTOR + +")?maxReconnectDelay=1000&useExponentialBackOff=false"; + + private final String SEQ_NUM_PROPERTY = "seqNum"; + + final int MESSAGE_LENGTH_BYTES = 75 * 1024; + final long SLEEP_BETWEEN_SEND_MS = 25; + final int NUM_SENDERS_AND_RECEIVERS = 10; + final Object brokerLock = new Object(); + + private static final long DEFAULT_BROKER_STOP_PERIOD = 10 * 1000; + private static final long DEFAULT_NUM_TO_SEND = 1400; + + long brokerStopPeriod = DEFAULT_BROKER_STOP_PERIOD; + long numtoSend = DEFAULT_NUM_TO_SEND; + long sleepBetweenSend = SLEEP_BETWEEN_SEND_MS; + String brokerURL = DEFAULT_BROKER_URL; + + int numBrokerRestarts = 0; + final static int MAX_BROKER_RESTARTS = 4; + BrokerService broker; + Vector exceptions = new Vector(); + + protected File dataDirFile; + final LoggingBrokerPlugin[] plugins = new LoggingBrokerPlugin[]{new LoggingBrokerPlugin()}; + + + public void createBroker(Configurer configurer) throws Exception { + broker = new BrokerService(); + configurePersistenceAdapter(broker); + + broker.getSystemUsage().getMemoryUsage().setLimit(MESSAGE_LENGTH_BYTES * 200 * NUM_SENDERS_AND_RECEIVERS); + + broker.addConnector(BROKER_CONNECTOR); + broker.setBrokerName(testName.getMethodName()); + broker.setDataDirectoryFile(dataDirFile); + if (configurer != null) { + configurer.configure(broker); + } + broker.start(); + } + + protected void configurePersistenceAdapter(BrokerService brokerService) throws Exception { + } + + @Before + public void setUp() throws Exception { + LOG.debug("Starting test {}", testName.getMethodName()); + dataDirFile = new File("target/"+ testName.getMethodName()); + numtoSend = DEFAULT_NUM_TO_SEND; + brokerStopPeriod = DEFAULT_BROKER_STOP_PERIOD; + sleepBetweenSend = SLEEP_BETWEEN_SEND_MS; + brokerURL = DEFAULT_BROKER_URL; + } + + @After + public void tearDown() throws Exception { + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new TeardownTask(brokerLock, broker)); + try { + LOG.debug("Teardown started."); + long start = System.currentTimeMillis(); + Boolean result = future.get(30, TimeUnit.SECONDS); + long finish = System.currentTimeMillis(); + LOG.debug("Result of teardown: {} after {} ms ", result, (finish - start)); + } catch (TimeoutException e) { + fail("Teardown timed out"); + AutoFailTestSupport.dumpAllThreads(testName.getMethodName()); + } + executor.shutdownNow(); + exceptions.clear(); + } + + private String buildLongString() { + final StringBuilder stringBuilder = new StringBuilder( + MESSAGE_LENGTH_BYTES); + for (int i = 0; i < MESSAGE_LENGTH_BYTES; ++i) { + stringBuilder.append((int) (Math.random() * 10)); + } + return stringBuilder.toString(); + } + + HashSet connections = new HashSet(); + private class Receiver implements MessageListener { + + private final javax.jms.Destination dest; + + private final Connection connection; + + private final Session session; + + private final MessageConsumer messageConsumer; + + private volatile long nextExpectedSeqNum = 0; + + private final boolean transactional; + + private String lastId = null; + + public Receiver(javax.jms.Destination dest, boolean transactional) throws JMSException { + this.dest = dest; + this.transactional = transactional; + connection = new ActiveMQConnectionFactory(brokerURL) + .createConnection(); + connection.setClientID(dest.toString()); + session = connection.createSession(transactional, transactional ? Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE); + if (ActiveMQDestination.transform(dest).isTopic()) { + messageConsumer = session.createDurableSubscriber((Topic) dest, dest.toString()); + } else { + messageConsumer = session.createConsumer(dest); + } + messageConsumer.setMessageListener(this); + connection.start(); + connections.add(connection); + } + + public void close() throws JMSException { + connection.close(); + } + + public long getNextExpectedSeqNo() { + return nextExpectedSeqNum; + } + + final int TRANSACITON_BATCH = 500; + boolean resumeOnNextOrPreviousIsOk = false; + public void onMessage(Message message) { + try { + final long seqNum = message.getLongProperty(SEQ_NUM_PROPERTY); + if ((seqNum % TRANSACITON_BATCH) == 0) { + LOG.info(dest + " received " + seqNum); + + if (transactional) { + LOG.info("committing.."); + session.commit(); + } + } + if (resumeOnNextOrPreviousIsOk) { + // after an indoubt commit we need to accept what we get (within reason) + if (seqNum != nextExpectedSeqNum) { + if (seqNum == nextExpectedSeqNum - (TRANSACITON_BATCH -1)) { + nextExpectedSeqNum -= (TRANSACITON_BATCH -1); + LOG.info("In doubt commit failed, getting replay at:" + nextExpectedSeqNum); + } + } + resumeOnNextOrPreviousIsOk = false; + } + if (seqNum != nextExpectedSeqNum) { + LOG.warn(dest + " received " + seqNum + + " in msg: " + message.getJMSMessageID() + + " expected " + + nextExpectedSeqNum + + ", lastId: " + lastId + + ", message:" + message); + fail(dest + " received " + seqNum + " expected " + + nextExpectedSeqNum); + } + ++nextExpectedSeqNum; + lastId = message.getJMSMessageID(); + } catch (TransactionRolledBackException expectedSometimesOnFailoverRecovery) { + LOG.info("got rollback: " + expectedSometimesOnFailoverRecovery); + if (expectedSometimesOnFailoverRecovery.getMessage().contains("completion in doubt")) { + // in doubt - either commit command or reply missing + // don't know if we will get a replay + resumeOnNextOrPreviousIsOk = true; + nextExpectedSeqNum++; + LOG.info("in doubt transaction completion: ok to get next or previous batch. next:" + nextExpectedSeqNum); + } else { + resumeOnNextOrPreviousIsOk = false; + // batch will be replayed + nextExpectedSeqNum -= (TRANSACITON_BATCH -1); + } + + } catch (Throwable e) { + LOG.error(dest + " onMessage error", e); + exceptions.add(e); + } + } + + } + + private class Sender implements Runnable { + + private final javax.jms.Destination dest; + + private final Connection connection; + + private final Session session; + + private final MessageProducer messageProducer; + + private volatile long nextSequenceNumber = 0; + + public Sender(javax.jms.Destination dest) throws JMSException { + this.dest = dest; + connection = new ActiveMQConnectionFactory(brokerURL) + .createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + messageProducer = session.createProducer(dest); + messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + connections.add(connection); + } + + public void run() { + final String longString = buildLongString(); + while (nextSequenceNumber < numtoSend) { + try { + final Message message = session + .createTextMessage(longString); + message.setLongProperty(SEQ_NUM_PROPERTY, + nextSequenceNumber); + ++nextSequenceNumber; + messageProducer.send(message); + + if ((nextSequenceNumber % 500) == 0) { + LOG.info(dest + " sent " + nextSequenceNumber); + } + + } catch (javax.jms.IllegalStateException e) { + LOG.error(dest + " bailing on send error", e); + exceptions.add(e); + break; + } catch (Exception e) { + LOG.error(dest + " send error", e); + exceptions.add(e); + } + if (sleepBetweenSend > 0) { + try { + Thread.sleep(sleepBetweenSend); + } catch (InterruptedException e) { + LOG.warn(dest + " sleep interrupted", e); + } + } + } + try { + connection.close(); + } catch (JMSException ignored) { + } + } + } + + // attempt to simply replicate leveldb failure. no joy yet + public void x_testRestartReReceive() throws Exception { + createBroker(new Configurer() { + public void configure(BrokerService broker) throws Exception { + broker.deleteAllMessages(); + } + }); + + final javax.jms.Destination destination = + ActiveMQDestination.createDestination("test.dest.X", ActiveMQDestination.QUEUE_TYPE); + Thread thread = new Thread(new Sender(destination)); + thread.start(); + thread.join(); + + Connection connection = new ActiveMQConnectionFactory(brokerURL).createConnection(); + connection.setClientID(destination.toString()); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer messageConsumer = session.createConsumer(destination); + connection.start(); + + int batch = 200; + long expectedSeq; + + final TimerTask restartTask = schedualRestartTask(null, new Configurer() { + public void configure(BrokerService broker) throws Exception { + } + }); + + expectedSeq = 0; + for (int s = 0; s < 4; s++) { + for (int i = 0; i < batch; i++) { + Message message = messageConsumer.receive(20000); + assertNotNull("s:" + s + ", i:" + i, message); + final long seqNum = message.getLongProperty(SEQ_NUM_PROPERTY); + assertEquals("expected order s:" + s, expectedSeq++, seqNum); + + if (i > 0 && i%600 == 0) { + LOG.info("Commit on %5"); + // session.commit(); + } + } + restartTask.run(); + } + + } + + // no need to run this unless there are some issues with the others + public void vanilaVerify_testOrder() throws Exception { + + createBroker(new Configurer() { + public void configure(BrokerService broker) throws Exception { + broker.deleteAllMessages(); + } + }); + + verifyOrderedMessageReceipt(); + verifyStats(false); + } + + @Test(timeout = 5 * 60 * 1000) + public void testOrderWithRestart() throws Exception { + createBroker(new Configurer() { + public void configure(BrokerService broker) throws Exception { + broker.deleteAllMessages(); + } + }); + + final Timer timer = new Timer(); + schedualRestartTask(timer, new Configurer() { + public void configure(BrokerService broker) throws Exception { + } + }); + + try { + verifyOrderedMessageReceipt(); + } finally { + timer.cancel(); + } + + verifyStats(true); + } + + @Test(timeout = 5 * 60 * 1000) + public void testTopicOrderWithRestart() throws Exception { + createBroker(new Configurer() { + public void configure(BrokerService broker) throws Exception { + broker.deleteAllMessages(); + } + }); + + final Timer timer = new Timer(); + schedualRestartTask(timer, null); + + try { + verifyOrderedMessageReceipt(ActiveMQDestination.TOPIC_TYPE); + } finally { + timer.cancel(); + } + + verifyStats(true); + } + + @Test(timeout = 5 * 60 * 1000) + public void testQueueTransactionalOrderWithRestart() throws Exception { + doTestTransactionalOrderWithRestart(ActiveMQDestination.QUEUE_TYPE); + } + + @Test(timeout = 5 * 60 * 1000) + public void testTopicTransactionalOrderWithRestart() throws Exception { + doTestTransactionalOrderWithRestart(ActiveMQDestination.TOPIC_TYPE); + } + + public void doTestTransactionalOrderWithRestart(byte destinationType) throws Exception { + numtoSend = 10000; + sleepBetweenSend = 3; + brokerStopPeriod = 10 * 1000; + + createBroker(new Configurer() { + public void configure(BrokerService broker) throws Exception { + broker.deleteAllMessages(); + } + }); + + final Timer timer = new Timer(); + schedualRestartTask(timer, null); + + try { + verifyOrderedMessageReceipt(destinationType, 1, true); + } finally { + timer.cancel(); + } + + verifyStats(true); + } + + private void verifyStats(boolean brokerRestarts) throws Exception { + RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + + for (Destination dest : regionBroker.getQueueRegion().getDestinationMap().values()) { + DestinationStatistics stats = dest.getDestinationStatistics(); + if (brokerRestarts) { + // all bets are off w.r.t stats as there may be duplicate sends and duplicate + // dispatches, all of which will be suppressed - either by the reference store + // not allowing duplicate references or consumers acking duplicates + LOG.info("with restart: not asserting qneue/dequeue stat match for: " + dest.getName() + + " " + stats.getEnqueues().getCount() + " <= " +stats.getDequeues().getCount()); + } else { + assertEquals("qneue/dequeue match for: " + dest.getName(), + stats.getEnqueues().getCount(), stats.getDequeues().getCount()); + } + } + } + + private TimerTask schedualRestartTask(final Timer timer, final Configurer configurer) { + class RestartTask extends TimerTask { + public void run() { + synchronized (brokerLock) { + LOG.info("stopping broker.."); + try { + broker.stop(); + broker.waitUntilStopped(); + } catch (Exception e) { + LOG.error("ex on broker stop", e); + exceptions.add(e); + } + LOG.info("restarting broker"); + try { + createBroker(configurer); + broker.waitUntilStarted(); + } catch (Exception e) { + LOG.error("ex on broker restart", e); + exceptions.add(e); + } + } + if (++numBrokerRestarts < MAX_BROKER_RESTARTS && timer != null) { + // do it again + try { + timer.schedule(new RestartTask(), brokerStopPeriod); + } catch (IllegalStateException ignore_alreadyCancelled) { + } + } else { + LOG.info("no longer stopping broker on reaching Max restarts: " + MAX_BROKER_RESTARTS); + } + } + } + RestartTask task = new RestartTask(); + if (timer != null) { + timer.schedule(task, brokerStopPeriod); + } + return task; + } + + private void verifyOrderedMessageReceipt(byte destinationType) throws Exception { + verifyOrderedMessageReceipt(destinationType, NUM_SENDERS_AND_RECEIVERS, false); + } + + private void verifyOrderedMessageReceipt() throws Exception { + verifyOrderedMessageReceipt(ActiveMQDestination.QUEUE_TYPE, NUM_SENDERS_AND_RECEIVERS, false); + } + + private void verifyOrderedMessageReceipt(byte destinationType, int concurrentPairs, boolean transactional) throws Exception { + + Vector threads = new Vector(); + Vector receivers = new Vector(); + + for (int i = 0; i < concurrentPairs; ++i) { + final javax.jms.Destination destination = + ActiveMQDestination.createDestination("test.dest." + i, destinationType); + receivers.add(new Receiver(destination, transactional)); + Thread thread = new Thread(new Sender(destination)); + thread.start(); + threads.add(thread); + } + + final long expiry = System.currentTimeMillis() + 1000 * 60 * 4; + while(!threads.isEmpty() && exceptions.isEmpty() && System.currentTimeMillis() < expiry) { + Thread sendThread = threads.firstElement(); + sendThread.join(1000*30); + if (!sendThread.isAlive()) { + threads.remove(sendThread); + } else { + AutoFailTestSupport.dumpAllThreads("Send blocked"); + } + } + LOG.info("senders done..." + threads); + + while(!receivers.isEmpty() && System.currentTimeMillis() < expiry) { + Receiver receiver = receivers.firstElement(); + if (receiver.getNextExpectedSeqNo() >= numtoSend || !exceptions.isEmpty()) { + receiver.close(); + receivers.remove(receiver); + } + } + + for (Connection connection : connections) { + try { + connection.close(); + } catch (Exception ignored) {} + } + connections.clear(); + + assertTrue("No timeout waiting for senders/receivers to complete", System.currentTimeMillis() < expiry); + if (!exceptions.isEmpty()) { + exceptions.get(0).printStackTrace(); + } + + LOG.info("Dangling threads: " + threads); + for (Thread dangling : threads) { + dangling.interrupt(); + dangling.join(10*1000); + } + + assertTrue("No exceptions", exceptions.isEmpty()); + } + +} + +class TeardownTask implements Callable { + private Object brokerLock; + private BrokerService broker; + + public TeardownTask(Object brokerLock, BrokerService broker) { + this.brokerLock = brokerLock; + this.broker = broker; + } + + @Override + public Boolean call() throws Exception { + synchronized(brokerLock) { + if (broker!= null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + return Boolean.TRUE; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2171Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2171Test.java new file mode 100644 index 0000000000..f23f758916 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2171Test.java @@ -0,0 +1,146 @@ +/** + * 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.bugs; + +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; +import javax.jms.*; +import javax.jms.Queue; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class AMQ2171Test implements Thread.UncaughtExceptionHandler { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2171Test.class); + private static final String BROKER_URL = "tcp://localhost:0"; + private static final int QUEUE_SIZE = 100; + + private static BrokerService brokerService; + private static Queue destination; + + private String brokerUri; + private String brokerUriNoPrefetch; + private Collection exceptions = new CopyOnWriteArrayList(); + + @Before + public void setUp() throws Exception { + // Start an embedded broker up. + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.addConnector(BROKER_URL); + brokerService.start(); + + brokerUri = brokerService.getTransportConnectors().get(0).getPublishableConnectString().toString(); + brokerUriNoPrefetch = brokerUri + "?jms.prefetchPolicy.all=0"; + + destination = new ActiveMQQueue("Test"); + produce(brokerUri, QUEUE_SIZE); + } + + @Before + public void addHandler() { + Thread.setDefaultUncaughtExceptionHandler(this); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + } + + @Test(timeout = 10000) + public void testBrowsePrefetch() throws Exception { + runTest(brokerUri); + } + + @Test(timeout = 10000) + public void testBrowseNoPrefetch() throws Exception { + runTest(brokerUriNoPrefetch); + } + + private void runTest(String brokerURL) throws Exception { + + Connection connection = new ActiveMQConnectionFactory(brokerURL).createConnection(); + + try { + connection.start(); + + Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + @SuppressWarnings("unchecked") + Enumeration unread = (Enumeration) session.createBrowser(destination).getEnumeration(); + + int count = 0; + while (unread.hasMoreElements()) { + unread.nextElement(); + count++; + } + + assertEquals(QUEUE_SIZE, count); + assertTrue(exceptions.isEmpty()); + } finally { + try { + connection.close(); + } catch (JMSException e) { + exceptions.add(e); + } + } + } + + private static void produce(String brokerURL, int count) throws Exception { + Connection connection = null; + + try { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL); + connection = factory.createConnection(); + Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(0); + connection.start(); + + for (int i = 0; i < count; i++) { + int id = i + 1; + TextMessage message = session.createTextMessage("Message " + id); + message.setIntProperty("MsgNumber", id); + producer.send(message); + + if (id % 500 == 0) { + LOG.info("sent " + id + ", ith " + message); + } + } + } finally { + try { + if (connection != null) { + connection.close(); + } + } catch (Throwable e) { + } + } + } + + public void uncaughtException(Thread t, Throwable e) { + exceptions.add(e); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2200Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2200Test.java new file mode 100644 index 0000000000..0903e56fad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2200Test.java @@ -0,0 +1,100 @@ +/** + * 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.bugs; + +import static org.junit.Assert.*; +import java.io.File; +import java.util.concurrent.TimeUnit; + +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.TopicSubscriptionViewMBean; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ2200Test { + + private static final String bindAddress = "tcp://0.0.0.0:0"; + private BrokerService broker; + private ActiveMQConnectionFactory cf; + + @Before + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector(bindAddress); + String address = broker.getTransportConnectors().get(0).getPublishableConnectString(); + broker.start(); + broker.waitUntilStarted(); + + cf = new ActiveMQConnectionFactory(address); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test + public void testTopicSubscriptionView() throws Exception { + TopicConnection connection = cf.createTopicConnection(); + TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + + Topic destination = session.createTopic("TopicViewTestTopic"); + MessageConsumer consumer = session.createConsumer(destination); + assertNotNull(consumer); + TimeUnit.SECONDS.sleep(1); + + ObjectName subscriptionNames[] = broker.getAdminView().getTopicSubscribers(); + assertTrue(subscriptionNames.length > 0); + + boolean fail = true; + for(ObjectName name : subscriptionNames) { + if (name.toString().contains("TopicViewTestTopic")) { + TopicSubscriptionViewMBean sub = (TopicSubscriptionViewMBean) + broker.getManagementContext().newProxyInstance(name, TopicSubscriptionViewMBean.class, true); + assertNotNull(sub); + assertTrue(sub.getSessionId() != -1); + // Check that its the default value then configure something new. + assertTrue(sub.getMaximumPendingQueueSize() == -1); + sub.setMaximumPendingQueueSize(1000); + assertTrue(sub.getMaximumPendingQueueSize() != -1); + fail = false; + } + } + + if (fail) { + fail("Didn't find the TopicSubscriptionView"); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2213Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2213Test.java new file mode 100644 index 0000000000..f267a9933a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2213Test.java @@ -0,0 +1,104 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ2213Test +{ + BrokerService broker; + ConnectionFactory factory; + Connection connection; + Session session; + Queue queue; + MessageConsumer consumer; + + public void createBroker(boolean deleteAll) throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(deleteAll); + broker.setDataDirectory("target/AMQ3145Test"); + broker.setUseJmx(true); + broker.getManagementContext().setCreateConnector(false); + broker.addConnector("tcp://localhost:0"); + broker.start(); + broker.waitUntilStarted(); + factory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri().toString()); + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + } + + @Before + public void createBroker() throws Exception { + createBroker(true); + } + + @After + public void tearDown() throws Exception { + if (consumer != null) { + consumer.close(); + } + session.close(); + connection.stop(); + connection.close(); + broker.stop(); + } + + @Test + public void testEqualsGenericSession() throws JMSException + { + assertNotNull(this.connection); + Session sess = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + assertTrue(sess.equals(sess)); + } + + @Test + public void testEqualsTopicSession() throws JMSException + { + assertNotNull(this.connection); + assertTrue(this.connection instanceof TopicConnection); + TopicSession sess = ((TopicConnection)this.connection).createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + assertTrue(sess.equals(sess)); + } + + @Test + public void testEqualsQueueSession() throws JMSException + { + assertNotNull(this.connection); + assertTrue(this.connection instanceof QueueConnection); + QueueSession sess = ((QueueConnection)this.connection).createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + assertTrue(sess.equals(sess)); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2314Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2314Test.java new file mode 100644 index 0000000000..369385c8b3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2314Test.java @@ -0,0 +1,175 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.concurrent.CountDownLatch; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2314Test extends CombinationTestSupport { + + public boolean consumeAll = false; + public int deliveryMode = DeliveryMode.NON_PERSISTENT; + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2314Test.class); + private static final int MESSAGES_COUNT = 30000; + private static byte[] buf = new byte[1024]; + private BrokerService broker; + private String connectionUri; + + private static final long messageReceiveTimeout = 500L; + + Destination destination = new ActiveMQTopic("FooTwo"); + + public void testRemoveSlowSubscriberWhacksTempStore() throws Exception { + runProducerWithHungConsumer(); + } + + public void testMemoryUsageReleasedOnAllConsumed() throws Exception { + consumeAll = true; + runProducerWithHungConsumer(); + // do it again to ensure memory limits are decreased + runProducerWithHungConsumer(); + } + + public void runProducerWithHungConsumer() throws Exception { + + final CountDownLatch consumerContinue = new CountDownLatch(1); + final CountDownLatch consumerReady = new CountDownLatch(1); + + final long origTempUsage = broker.getSystemUsage().getTempUsage().getUsage(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + factory.setAlwaysSyncSend(true); + + // ensure messages are spooled to disk for this consumer + ActiveMQPrefetchPolicy prefetch = new ActiveMQPrefetchPolicy(); + prefetch.setTopicPrefetch(500); + factory.setPrefetchPolicy(prefetch); + final Connection connection = factory.createConnection(); + connection.start(); + + Thread producingThread = new Thread("Producing thread") { + public void run() { + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + for (int idx = 0; idx < MESSAGES_COUNT; ++idx) { + Message message = session.createTextMessage(new String(buf) + idx); + producer.send(message); + } + producer.close(); + session.close(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + Thread consumingThread = new Thread("Consuming thread") { + public void run() { + try { + int count = 0; + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + + while (consumer.receive(messageReceiveTimeout) == null) { + consumerReady.countDown(); + } + count++; + LOG.info("Received one... waiting"); + consumerContinue.await(); + if (consumeAll) { + LOG.info("Consuming the rest of the messages..."); + while (consumer.receive(messageReceiveTimeout) != null) { + count++; + } + } + LOG.info("consumer session closing: consumed count: " + count); + session.close(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + consumingThread.start(); + consumerReady.await(); + + producingThread.start(); + producingThread.join(); + + final long tempUsageBySubscription = broker.getSystemUsage().getTempUsage().getUsage(); + LOG.info("Orig Usage: " + origTempUsage + ", currentUsage: " + tempUsageBySubscription); + assertTrue("some temp store has been used", tempUsageBySubscription != origTempUsage); + consumerContinue.countDown(); + consumingThread.join(); + connection.close(); + + LOG.info("Subscription Usage: " + tempUsageBySubscription + ", endUsage: " + + broker.getSystemUsage().getTempUsage().getUsage()); + + assertTrue("temp usage decreased with removed sub", Wait.waitFor(new Wait.Condition(){ + public boolean isSatisified() throws Exception { + return broker.getSystemUsage().getTempUsage().getUsage() < tempUsageBySubscription; + } + })); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.getSystemUsage().getMemoryUsage().setLimit(1024l*1024*64); + + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + public void tearDown() throws Exception { + broker.stop(); + } + + public static Test suite() { + return suite(AMQ2314Test.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2356Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2356Test.java new file mode 100644 index 0000000000..283dd92b45 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2356Test.java @@ -0,0 +1,190 @@ +/** + * 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.bugs; + +import java.io.File; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBStore; + +/* + A AMQ2356Test + We have an environment where we have a very large number of destinations. + In an effort to reduce the number of threads I have set the options + -Dorg.apache.activemq.UseDedicatedTaskRunner=false + + and + + + + Unfortunately this very quickly leads to deadlocked queues. + + My environment is: + + ActiveMQ 5.2 Ubunty Jaunty kernel 2.6.28-14-generic #47-Ubuntu SMP (although only a single core on my system) + TCP transportConnector + + To reproduce the bug (which I can do 100% of the time) I connect 5 consumers (AUTO_ACK) to 5 different queues. + Then I start 5 producers and pair them up with a consumer on a queue, and they start sending PERSISTENT messages. + I've set the producer to send 100 messages and disconnect, and the consumer to receive 100 messages and disconnect. + The first pair usually gets through their 100 messages and disconnect, at which point all the other pairs have + deadlocked at less than 30 messages each. + */ +public class AMQ2356Test extends TestCase { + protected static final int MESSAGE_COUNT = 1000; + protected static final int NUMBER_OF_PAIRS = 10; + protected BrokerService broker; + protected String brokerURL = ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL; + protected int destinationCount; + + public void testScenario() throws Exception { + for (int i = 0; i < NUMBER_OF_PAIRS; i++) { + ActiveMQQueue queue = new ActiveMQQueue(getClass().getName() + ":" + i); + ProducerConsumerPair cp = new ProducerConsumerPair(); + cp.start(this.brokerURL, queue, MESSAGE_COUNT); + cp.testRun(); + cp.stop(); + } + } + + protected Destination getDestination(Session session) throws JMSException { + String destinationName = getClass().getName() + "." + destinationCount++; + return session.createQueue(destinationName); + } + + @Override + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + File dataFileDir = new File("target/test-amq-data/bugs/AMQ2356/kahadb"); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(dataFileDir); + answer.setUseJmx(false); + // Setup a destination policy where it takes only 1 message at a time. + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setOptimizedDispatch(true); + policyMap.setDefaultEntry(policy); + answer.setDestinationPolicy(policyMap); + + answer.setAdvisorySupport(false); + answer.setEnableStatistics(false); + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(brokerURL); + + } + + static class ProducerConsumerPair { + private Destination destination; + private MessageProducer producer; + private MessageConsumer consumer; + private Connection producerConnection; + private Connection consumerConnection; + private int numberOfMessages; + + ProducerConsumerPair() { + + } + + void start(String brokerURL, final Destination dest, int msgNum) throws Exception { + this.destination = dest; + this.numberOfMessages = msgNum; + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerURL); + this.producerConnection = cf.createConnection(); + this.producerConnection.start(); + this.consumerConnection = cf.createConnection(); + this.consumerConnection.start(); + this.producer = createProducer(this.producerConnection); + this.consumer = createConsumer(this.consumerConnection); + } + + void testRun() throws Exception { + + Session s = this.producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + for (int i = 0; i < this.numberOfMessages; i++) { + BytesMessage msg = s.createBytesMessage(); + msg.writeBytes(new byte[1024]); + this.producer.send(msg); + } + int received = 0; + for (int i = 0; i < this.numberOfMessages; i++) { + Message msg = this.consumer.receive(); + assertNotNull(msg); + received++; + } + assertEquals("Messages received on " + this.destination, this.numberOfMessages, received); + + } + + void stop() throws Exception { + if (this.producerConnection != null) { + this.producerConnection.close(); + } + if (this.consumerConnection != null) { + this.consumerConnection.close(); + } + } + + private MessageProducer createProducer(Connection connection) throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer result = session.createProducer(this.destination); + return result; + } + + private MessageConsumer createConsumer(Connection connection) throws Exception { + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer result = session.createConsumer(this.destination); + return result; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2364Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2364Test.java new file mode 100644 index 0000000000..15d24d5cd4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2364Test.java @@ -0,0 +1,113 @@ +/** + * 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.bugs; +//package org.apache.activemq.transport.failover; + +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Field; +import java.net.URI; +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.state.ConnectionState; +import org.apache.activemq.state.ConnectionStateTracker; +import org.apache.activemq.state.TransactionState; +import org.apache.activemq.transport.MutexTransport; +import org.apache.activemq.transport.ResponseCorrelator; +import org.apache.activemq.transport.failover.FailoverTransport; +import org.junit.Test; + + +public class AMQ2364Test { + + @SuppressWarnings("unchecked") + @Test + public void testRollbackLeak() throws Exception { + + int messageCount = 1000; + URI failoverUri = new URI("failover:(vm://localhost)?jms.redeliveryPolicy.maximumRedeliveries=0"); + + Destination dest = new ActiveMQQueue("Failover.Leak"); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(failoverUri); + ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + + MessageProducer producer = session.createProducer(dest); + + for (int i = 0; i < messageCount; ++i) + producer.send(session.createTextMessage("Test message #" + i)); + producer.close(); + session.commit(); + + MessageConsumer consumer = session.createConsumer(dest); + + final CountDownLatch latch = new CountDownLatch(messageCount); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message msg) { + try { + session.rollback(); + } catch (JMSException e) { + e.printStackTrace(); + } finally { + latch.countDown(); + } + } + }); + + latch.await(); + consumer.close(); + session.close(); + + ResponseCorrelator respCorr = (ResponseCorrelator) connection.getTransport(); + MutexTransport mutexTrans = (MutexTransport) respCorr.getNext(); + FailoverTransport failoverTrans = (FailoverTransport) mutexTrans.getNext(); + Field stateTrackerField = FailoverTransport.class.getDeclaredField("stateTracker"); + stateTrackerField.setAccessible(true); + ConnectionStateTracker stateTracker = (ConnectionStateTracker) stateTrackerField.get(failoverTrans); + Field statesField = ConnectionStateTracker.class.getDeclaredField("connectionStates"); + statesField.setAccessible(true); + ConcurrentHashMap states = + (ConcurrentHashMap) statesField.get(stateTracker); + + ConnectionState state = states.get(connection.getConnectionInfo().getConnectionId()); + + Collection transactionStates = state.getTransactionStates(); + + connection.stop(); + connection.close(); + + assertEquals("Transaction states not cleaned up", 0,transactionStates.size()); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2383Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2383Test.java new file mode 100644 index 0000000000..49c2366cf9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2383Test.java @@ -0,0 +1,63 @@ +/** + * 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.bugs; + + +import static org.junit.Assert.*; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.Test; + +public class AMQ2383Test { + + @Test + public void activeMQTest() throws Exception { + Destination dest = ActiveMQQueue.createDestination("testQueue", ActiveMQQueue.QUEUE_TYPE); + ConnectionFactory factory = new ActiveMQConnectionFactory( + "vm://localhost?broker.useJmx=false&broker.persistent=false"); + Connection producerConnection = factory.createConnection(); + producerConnection.start(); + Connection consumerConnection = factory.createConnection(); + consumerConnection.start(); + + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(dest); + TextMessage sentMsg = producerSession.createTextMessage("test..."); + producer.send(sentMsg); + producerSession.close(); + + Session consumerSession = consumerConnection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = consumerSession.createConsumer(dest); + TextMessage receivedMsg = (TextMessage)consumer.receive(); + consumerSession.rollback(); + consumerSession.close(); + + assertEquals(sentMsg, receivedMsg); + + producerConnection.close(); + consumerConnection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2401Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2401Test.java new file mode 100644 index 0000000000..74f920fb85 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2401Test.java @@ -0,0 +1,237 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An AMQ-2401 Test + */ +public class AMQ2401Test extends TestCase implements MessageListener { + private BrokerService broker; + private ActiveMQConnectionFactory factory; + private static final int SEND_COUNT = 500; + private static final int CONSUMER_COUNT = 50; + private static final int PRODUCER_COUNT = 1; + private static final int LOG_INTERVAL = 10; + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2401Test.class); + + private final ArrayList services = new ArrayList(CONSUMER_COUNT + PRODUCER_COUNT); + private int count = 0; + private CountDownLatch latch; + + @Override + protected void setUp() throws Exception { + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "test-data" + File.separator + "AMQ2401Test"); + broker.setDeleteAllMessagesOnStartup(true); + String connectionUri = broker.addConnector("tcp://0.0.0.0:0").getPublishableConnectString(); + PolicyMap policies = new PolicyMap(); + PolicyEntry entry = new PolicyEntry(); + entry.setMemoryLimit(1024 * 100); + entry.setProducerFlowControl(true); + entry.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + entry.setQueue(">"); + policies.setDefaultEntry(entry); + broker.setDestinationPolicy(policies); + broker.setUseJmx(false); + broker.start(); + broker.waitUntilStarted(); + + factory = new ActiveMQConnectionFactory(connectionUri); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + public void testDupsOk() throws Exception { + + TestProducer p = null; + TestConsumer c = null; + try { + latch = new CountDownLatch(SEND_COUNT); + + for (int i = 0; i < CONSUMER_COUNT; i++) { + TestConsumer consumer = new TestConsumer(); + consumer.start(); + services.add(consumer); + } + for (int i = 0; i < PRODUCER_COUNT; i++) { + TestProducer producer = new TestProducer(); + producer.start(); + services.add(producer); + } + + waitForMessageReceipt(TimeUnit.SECONDS.toMillis(30)); + } finally { + if (p != null) { + p.close(); + } + + if (c != null) { + c.close(); + } + } + } + + @Override + public void onMessage(Message message) { + latch.countDown(); + if (++count % LOG_INTERVAL == 0) { + LOG.debug("Received message " + count); + } + + try { + Thread.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + /** + * @throws InterruptedException + * @throws TimeoutException + */ + private void waitForMessageReceipt(long timeout) throws InterruptedException, TimeoutException { + if (!latch.await(timeout, TimeUnit.MILLISECONDS)) { + throw new TimeoutException(String.format("Consumner didn't receive expected # of messages, %d of %d received.", latch.getCount(), SEND_COUNT)); + } + } + + private interface Service { + public void start() throws Exception; + public void close(); + } + + private class TestProducer implements Runnable, Service { + Thread thread; + BytesMessage message; + + Connection connection; + Session session; + MessageProducer producer; + + TestProducer() throws Exception { + thread = new Thread(this, "TestProducer"); + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + producer = session.createProducer(session.createQueue("AMQ2401Test")); + } + + @Override + public void start() { + thread.start(); + } + + @Override + public void run() { + + int count = SEND_COUNT / PRODUCER_COUNT; + for (int i = 1; i <= count; i++) { + try { + if ((i % LOG_INTERVAL) == 0) { + LOG.debug("Sending: " + i); + } + message = session.createBytesMessage(); + message.writeBytes(new byte[1024]); + producer.send(message); + } catch (JMSException jmse) { + jmse.printStackTrace(); + break; + } + } + } + + @Override + public void close() { + try { + connection.close(); + } catch (JMSException e) { + } + } + } + + private class TestConsumer implements Runnable, Service { + ActiveMQConnection connection; + Session session; + MessageConsumer consumer; + + TestConsumer() throws Exception { + factory.setOptimizeAcknowledge(false); + connection = (ActiveMQConnection) factory.createConnection(); + + session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + consumer = session.createConsumer(session.createQueue("AMQ2401Test")); + + consumer.setMessageListener(AMQ2401Test.this); + } + + @Override + public void start() throws Exception { + connection.start(); + } + + @Override + public void close() { + try { + connection.close(); + } catch (JMSException e) { + } + } + + @Override + public void run() { + while (latch.getCount() > 0) { + try { + onMessage(consumer.receive()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2413Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2413Test.java new file mode 100644 index 0000000000..25a95bcb43 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2413Test.java @@ -0,0 +1,346 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Vector; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2413Test extends CombinationTestSupport implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(AMQ2413Test.class); + BrokerService broker; + private ActiveMQConnectionFactory factory; + + private static final int HANG_THRESHOLD = 60; + private static final int SEND_COUNT = 1000; + private static final int RECEIVER_THINK_TIME = 1; + private static final int CONSUMER_COUNT = 1; + private static final int PRODUCER_COUNT = 50; + private static final int TO_SEND = SEND_COUNT / PRODUCER_COUNT; + + public int deliveryMode = DeliveryMode.NON_PERSISTENT; + public int ackMode = Session.DUPS_OK_ACKNOWLEDGE; + public boolean useVMCursor = false; + public boolean useOptimizeAcks = false; + + private final ArrayList services = new ArrayList(CONSUMER_COUNT + PRODUCER_COUNT); + AtomicInteger count = new AtomicInteger(0); + Semaphore receivedMessages; + AtomicBoolean running = new AtomicBoolean(false); + + public void initCombos() { + addCombinationValues("deliveryMode", new Object[] { DeliveryMode.PERSISTENT, DeliveryMode.NON_PERSISTENT }); + addCombinationValues("ackMode", new Object[] { Session.DUPS_OK_ACKNOWLEDGE, Session.AUTO_ACKNOWLEDGE }); + addCombinationValues("useVMCursor", new Object[] { true, false }); + // addCombinationValues("useOptimizeAcks", new Object[] {true, false}); + } + + @Override + protected void setUp() throws Exception { + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "test-data" + File.separator + "AMQ2401Test"); + broker.setDeleteAllMessagesOnStartup(true); + + KahaDBPersistenceAdapter kahaDb = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + kahaDb.setConcurrentStoreAndDispatchQueues(false); + broker.addConnector("tcp://0.0.0.0:2401"); + PolicyMap policies = new PolicyMap(); + PolicyEntry entry = new PolicyEntry(); + entry.setMemoryLimit(1024 * 1024); + entry.setProducerFlowControl(true); + if (useVMCursor) { + entry.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + } + entry.setQueue(">"); + policies.setDefaultEntry(entry); + broker.setDestinationPolicy(policies); + broker.start(); + broker.waitUntilStarted(); + + count.set(0); + receivedMessages = new Semaphore(0); + + factory = new ActiveMQConnectionFactory("tcp://0.0.0.0:2401"); + // factory = new ActiveMQConnectionFactory("vm://localhost?broker.useJmx=false&broker.persistent=false"); + setAutoFail(true); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + running.set(false); + for (Service service : services) { + service.close(); + } + + broker.stop(); + broker.waitUntilStopped(); + + super.tearDown(); + } + + public void testReceipt() throws Exception { + + running.set(true); + TestProducer p = null; + TestConsumer c = null; + try { + + for (int i = 0; i < CONSUMER_COUNT; i++) { + TestConsumer consumer = new TestConsumer(); + consumer.start(); + services.add(consumer); + } + for (int i = 0; i < PRODUCER_COUNT; i++) { + TestProducer producer = new TestProducer(i); + producer.start(); + services.add(producer); + } + waitForMessageReceipt(); + + } finally { + if (p != null) { + p.close(); + } + + if (c != null) { + c.close(); + } + } + + } + + /* + * (non-Javadoc) + * + * @see javax.jms.MessageListener#onMessage(javax.jms.Message) + */ + @Override + public void onMessage(Message message) { + receivedMessages.release(); + if (count.incrementAndGet() % 100 == 0) { + LOG.info("Received message " + count); + } + track(message); + if (RECEIVER_THINK_TIME > 0) { + try { + Thread.sleep(RECEIVER_THINK_TIME); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + } + + HashMap tracker = new HashMap(); + + private synchronized void track(Message message) { + try { + MessageId id = new MessageId(message.getJMSMessageID()); + ProducerId pid = id.getProducerId(); + int seq = (int) id.getProducerSequenceId(); + boolean[] ids = tracker.get(pid); + if (ids == null) { + ids = new boolean[TO_SEND + 1]; + ids[seq] = true; + tracker.put(pid, ids); + } else { + assertTrue("not already received: " + id, !ids[seq]); + ids[seq] = true; + } + } catch (Exception e) { + LOG.error(e.toString()); + } + } + + /** + * @throws InterruptedException + * @throws TimeoutException + * + */ + private void waitForMessageReceipt() throws InterruptedException, TimeoutException { + try { + while (count.get() < SEND_COUNT) { + if (!receivedMessages.tryAcquire(HANG_THRESHOLD, TimeUnit.SECONDS)) { + if (count.get() == SEND_COUNT) + break; + verifyTracking(); + throw new TimeoutException("@count=" + count.get() + " Message not received for more than " + HANG_THRESHOLD + " seconds"); + } + } + } finally { + running.set(false); + } + } + + private void verifyTracking() { + Vector missing = new Vector(); + for (ProducerId pid : tracker.keySet()) { + boolean[] ids = tracker.get(pid); + for (int i = 1; i < TO_SEND + 1; i++) { + if (!ids[i]) { + missing.add(new MessageId(pid, i)); + } + } + } + assertTrue("No missing messages: " + missing, missing.isEmpty()); + } + + private interface Service { + public void start() throws Exception; + + public void close(); + } + + private class TestProducer implements Runnable, Service { + Thread thread; + BytesMessage message; + Connection connection; + Session session; + MessageProducer producer; + + TestProducer(int id) throws Exception { + thread = new Thread(this, "TestProducer-" + id); + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + producer = session.createProducer(session.createQueue("AMQ2401Test")); + } + + @Override + public void start() { + thread.start(); + } + + @Override + public void run() { + + int i = 1; + for (; i <= TO_SEND; i++) { + try { + + if (+i % 100 == 0) { + LOG.info(Thread.currentThread().getName() + " Sending message " + i); + } + message = session.createBytesMessage(); + message.writeBytes(new byte[1024]); + producer.setDeliveryMode(deliveryMode); + producer.send(message); + } catch (JMSException jmse) { + jmse.printStackTrace(); + break; + } + } + LOG.info(Thread.currentThread().getName() + " Sent: " + (i - 1)); + } + + @Override + public void close() { + try { + connection.close(); + } catch (JMSException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + private class TestConsumer implements Runnable, Service { + ActiveMQConnection connection; + Session session; + MessageConsumer consumer; + + TestConsumer() throws Exception { + factory.setOptimizeAcknowledge(false); + connection = (ActiveMQConnection) factory.createConnection(); + if (useOptimizeAcks) { + connection.setOptimizeAcknowledge(true); + } + + session = connection.createSession(false, ackMode); + consumer = session.createConsumer(session.createQueue("AMQ2401Test")); + + consumer.setMessageListener(AMQ2413Test.this); + } + + @Override + public void start() throws Exception { + connection.start(); + } + + @Override + public void close() { + try { + connection.close(); + } catch (JMSException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /* + * (non-Javadoc) + * + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + while (running.get()) { + try { + onMessage(consumer.receive()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + public static Test suite() { + return suite(AMQ2413Test.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2439Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2439Test.java new file mode 100644 index 0000000000..cd447f4108 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2439Test.java @@ -0,0 +1,92 @@ +/** + * 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.bugs; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2439Test extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(AMQ2439Test.class); + Destination dest; + + + public void testDuplicatesThroughNetwork() throws Exception { + assertEquals("received expected amount", 500, receiveExactMessages("BrokerB", 500)); + assertEquals("received expected amount", 500, receiveExactMessages("BrokerB", 500)); + validateQueueStats(); + } + + private void validateQueueStats() throws Exception { + final BrokerView brokerView = brokers.get("BrokerA").broker.getAdminView(); + assertEquals("enequeue is correct", 1000, brokerView.getTotalEnqueueCount()); + + assertTrue("dequeue is correct", Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + LOG.info("dequeue count (want 1000), is : " + brokerView.getTotalDequeueCount()); + return 1000 == brokerView.getTotalDequeueCount(); + } + })); + } + + protected int receiveExactMessages(String brokerName, int msgCount) throws Exception { + + BrokerItem brokerItem = brokers.get(brokerName); + Connection connection = brokerItem.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(dest); + + Message msg; + int i; + for (i = 0; i < msgCount; i++) { + msg = consumer.receive(1000); + if (msg == null) { + break; + } + } + + connection.close(); + brokerItem.connections.remove(connection); + + return i; + } + + public void setUp() throws Exception { + super.setUp(); + createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=true&deleteAllMessagesOnStartup=true&advisorySupport=false")); + createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB?persistent=true&deleteAllMessagesOnStartup=true&useJmx=false")); + bridgeBrokers("BrokerA", "BrokerB"); + + startAllBrokers(); + + // Create queue + dest = createDestination("TEST.FOO", false); + sendMessages("BrokerA", dest, 1000); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2489Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2489Test.java new file mode 100644 index 0000000000..b581e6deb8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2489Test.java @@ -0,0 +1,226 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.TestSupport; +import org.apache.activemq.command.ActiveMQQueue; + +/** + * In CLIENT_ACKNOWLEDGE and INDIVIDUAL_ACKNOWLEDGE modes following exception + * occurs when ASYNCH consumers acknowledges messages in not in order they + * received the messages. + *

+ * Exception thrown on broker side: + *

+ * {@code javax.jms.JMSException: Could not correlate acknowledgment with + * dispatched message: MessageAck} + * + * @author daroo + */ +public class AMQ2489Test extends TestSupport { + private final static String SEQ_NUM_PROPERTY = "seqNum"; + + private final static int TOTAL_MESSAGES_CNT = 2; + private final static int CONSUMERS_CNT = 2; + + private final CountDownLatch LATCH = new CountDownLatch(TOTAL_MESSAGES_CNT); + + private Connection connection; + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + connection = null; + } + super.tearDown(); + } + + public void testUnorderedClientAcknowledge() throws Exception { + doUnorderedAck(Session.CLIENT_ACKNOWLEDGE); + } + + public void testUnorderedIndividualAcknowledge() throws Exception { + doUnorderedAck(ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE); + } + + /** + * Main test method + * + * @param acknowledgmentMode + * - ACK mode to be used by consumers + * @throws Exception + */ + protected void doUnorderedAck(int acknowledgmentMode) throws Exception { + List consumers = null; + Session producerSession = null; + + connection.start(); + // Because exception is thrown on broker side only, let's set up + // exception listener to get it + final TestExceptionListener exceptionListener = new TestExceptionListener(); + connection.setExceptionListener(exceptionListener); + try { + consumers = new ArrayList(); + // start customers + for (int i = 0; i < CONSUMERS_CNT; i++) { + consumers.add(new Consumer(acknowledgmentMode)); + } + + // produce few test messages + producerSession = connection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = producerSession + .createProducer(new ActiveMQQueue(getQueueName())); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + for (int i = 0; i < TOTAL_MESSAGES_CNT; i++) { + final Message message = producerSession + .createTextMessage("test"); + // assign each message sequence number + message.setIntProperty(SEQ_NUM_PROPERTY, i); + producer.send(message); + } + + // during each onMessage() calls consumers decreases the LATCH + // counter. + // + // so, let's wait till all messages are consumed. + // + LATCH.await(); + + // wait a bit more to give exception listener a chance be populated + // with + // broker's error + TimeUnit.SECONDS.sleep(1); + + assertFalse(exceptionListener.getStatusText(), exceptionListener.hasExceptions()); + + } finally { + if (producerSession != null) + producerSession.close(); + + if (consumers != null) { + for (Consumer c : consumers) { + c.close(); + } + } + } + } + + protected String getQueueName() { + return getClass().getName() + "." + getName(); + } + + public final class Consumer implements MessageListener { + final Session session; + + private Consumer(int acknowledgmentMode) { + try { + session = connection.createSession(false, acknowledgmentMode); + final Queue queue = session.createQueue(getQueueName() + + "?consumer.prefetchSize=1"); + final MessageConsumer consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + } catch (JMSException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public void onMessage(Message message) { + try { + // retrieve sequence number assigned by producer... + final int seqNum = message.getIntProperty(SEQ_NUM_PROPERTY); + + // ...and let's delay every second message a little bit before + // acknowledgment + if ((seqNum % 2) == 0) { + System.out.println("Delayed message sequence numeber: " + + seqNum); + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + message.acknowledge(); + } catch (JMSException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + // decrease LATCH counter in the main test method. + LATCH.countDown(); + } + } + + private void close() { + if (session != null) { + try { + session.close(); + } catch (JMSException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + } + } + + public final class TestExceptionListener implements ExceptionListener { + private final java.util.Queue exceptions = new ConcurrentLinkedQueue(); + + public void onException(JMSException e) { + exceptions.add(e); + } + + public boolean hasExceptions() { + return exceptions.isEmpty() == false; + } + + public String getStatusText() { + final StringBuilder str = new StringBuilder(); + str.append("Exceptions count on broker side: " + exceptions.size() + + ".\nMessages:\n"); + for (Exception e : exceptions) { + str.append(e.getMessage() + "\n\n"); + } + return str.toString(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2512Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2512Test.java new file mode 100644 index 0000000000..669066e1ee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2512Test.java @@ -0,0 +1,174 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.IOHelper; + +public class AMQ2512Test extends EmbeddedBrokerTestSupport { + private static Connection connection; + private final static String QUEUE_NAME = "dee.q"; + private final static int INITIAL_MESSAGES_CNT = 1000; + private final static int WORKER_INTERNAL_ITERATIONS = 100; + private final static int TOTAL_MESSAGES_CNT = INITIAL_MESSAGES_CNT * WORKER_INTERNAL_ITERATIONS + + INITIAL_MESSAGES_CNT; + private final static byte[] payload = new byte[5 * 1024]; + private final static String TEXT = new String(payload); + + private final static String PRP_INITIAL_ID = "initial-id"; + private final static String PRP_WORKER_ID = "worker-id"; + + private final static CountDownLatch LATCH = new CountDownLatch(TOTAL_MESSAGES_CNT); + + private final static AtomicInteger ON_MSG_COUNTER = new AtomicInteger(); + + public void testKahaDBFailure() throws Exception { + final ConnectionFactory fac = new ActiveMQConnectionFactory(this.bindAddress); + connection = fac.createConnection(); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue queue = session.createQueue(QUEUE_NAME); + final MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + final long startTime = System.nanoTime(); + + final List consumers = new ArrayList(); + for (int i = 0; i < 20; i++) { + consumers.add(new Consumer("worker-" + i)); + } + + for (int i = 0; i < INITIAL_MESSAGES_CNT; i++) { + final TextMessage msg = session.createTextMessage(TEXT); + msg.setStringProperty(PRP_INITIAL_ID, "initial-" + i); + producer.send(msg); + } + + LATCH.await(); + final long endTime = System.nanoTime(); + System.out.println("Total execution time = " + + TimeUnit.MILLISECONDS.convert(endTime - startTime, TimeUnit.NANOSECONDS) + " [ms]."); + System.out.println("Rate = " + TOTAL_MESSAGES_CNT + / TimeUnit.SECONDS.convert(endTime - startTime, TimeUnit.NANOSECONDS) + " [msg/s]."); + + for (Consumer c : consumers) { + c.close(); + } + connection.close(); + } + + private final static class Consumer implements MessageListener { + private final String name; + private final Session session; + private final MessageProducer producer; + + private Consumer(String name) { + this.name = name; + try { + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final Queue queue = session.createQueue(QUEUE_NAME + "?consumer.prefetchSize=10"); + producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + final MessageConsumer consumer = session.createConsumer(queue); + consumer.setMessageListener(this); + } catch (JMSException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public void onMessage(Message message) { + final TextMessage msg = (TextMessage) message; + try { + if (!msg.propertyExists(PRP_WORKER_ID)) { + for (int i = 0; i < WORKER_INTERNAL_ITERATIONS; i++) { + final TextMessage newMsg = session.createTextMessage(msg.getText()); + newMsg.setStringProperty(PRP_WORKER_ID, name + "-" + i); + newMsg.setStringProperty(PRP_INITIAL_ID, msg.getStringProperty(PRP_INITIAL_ID)); + producer.send(newMsg); + } + } + msg.acknowledge(); + + } catch (JMSException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + final int onMsgCounter = ON_MSG_COUNTER.getAndIncrement(); + if (onMsgCounter % 1000 == 0) { + System.out.println("message received: " + onMsgCounter); + } + LATCH.countDown(); + } + } + + private void close() { + if (session != null) { + try { + session.close(); + } catch (JMSException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + } + } + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://0.0.0.0:61617"; + super.setUp(); + } + + @Override + protected BrokerService createBroker() throws Exception { + File dataFileDir = new File("target/test-amq-2512/datadb"); + IOHelper.mkdirs(dataFileDir); + IOHelper.deleteChildren(dataFileDir); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(dataFileDir); + BrokerService answer = new BrokerService(); + answer.setPersistenceAdapter(kaha); + + kaha.setEnableJournalDiskSyncs(false); + //kaha.setIndexCacheSize(10); + answer.setDataDirectoryFile(dataFileDir); + answer.setUseJmx(false); + answer.addConnector(bindAddress); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2513Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2513Test.java new file mode 100644 index 0000000000..b9cfbd9c3c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2513Test.java @@ -0,0 +1,107 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.broker.jmx.ManagementContext; + +/** + * This unit test verifies an issue when + * javax.management.InstanceNotFoundException is thrown after subsequent startups when + * managementContext createConnector="false" + * + */ +public class AMQ2513Test extends TestCase { + + private BrokerService broker; + private String connectionUri; + + void createBroker(boolean deleteAllMessagesOnStartup) throws Exception { + broker = new BrokerService(); + broker.setBrokerName("localhost"); + broker.setUseJmx(true); + broker.setDeleteAllMessagesOnStartup(deleteAllMessagesOnStartup); + broker.addConnector("tcp://localhost:0"); + + ManagementContext ctx = new ManagementContext(); + //if createConnector == true everything is fine + ctx.setCreateConnector(false); + broker.setManagementContext(ctx); + + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + public void testJmx() throws Exception{ + createBroker(true); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createQueue("test")); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + producer.send(session.createTextMessage("test123")); + + DestinationViewMBean dv = createView(); + assertTrue(dv.getQueueSize() > 0); + + connection.close(); + + broker.stop(); + broker.waitUntilStopped(); + + createBroker(false); + factory = new ActiveMQConnectionFactory(connectionUri); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(session.createQueue("test")); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + producer.send(session.createTextMessage("test123")); + connection.close(); + + dv = createView(); + assertTrue(dv.getQueueSize() > 0); + + broker.stop(); + broker.waitUntilStopped(); + + } + + DestinationViewMBean createView() throws Exception { + String domain = "org.apache.activemq"; + ObjectName name = new ObjectName(domain + ":type=Broker,brokerName=localhost," + + "destinationType=Queue,destinationName=test"); + return (DestinationViewMBean) broker.getManagementContext().newProxyInstance(name, DestinationViewMBean.class, + true); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2528Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2528Test.java new file mode 100644 index 0000000000..80c036f0cb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2528Test.java @@ -0,0 +1,81 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.region.Queue; +import org.junit.Assert; + +/** + * This test demonstrates a bug in which calling + * Queue#removeMatchingMessages("") generates an exception, whereas the JMS + * specification states that an empty selector is valid. + */ +public class AMQ2528Test extends EmbeddedBrokerTestSupport { + + /** + * Setup the test so that the destination is a queue. + */ + protected void setUp() throws Exception { + useTopic = false; + super.setUp(); + } + + /** + * This test enqueues test messages to destination and then verifies that + * {@link Queue#removeMatchingMessages("")} removes all the messages. + */ + public void testRemoveMatchingMessages() throws Exception { + final int NUM_MESSAGES = 100; + final String MESSAGE_ID = "id"; + + // Enqueue the test messages. + Connection conn = createConnection(); + try { + conn.start(); + Session session = conn.createSession(false, + Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + for (int id = 0; id < NUM_MESSAGES; id++) { + Message message = session.createMessage(); + message.setIntProperty(MESSAGE_ID, id); + producer.send(message); + } + producer.close(); + session.close(); + } finally { + conn.close(); + } + + // Verify that half of the messages can be removed by selector. + Queue queue = (Queue) broker.getRegionBroker().getDestinations( + destination).iterator().next(); + + Assert.assertEquals(NUM_MESSAGES / 2, queue + .removeMatchingMessages(MESSAGE_ID + " < " + NUM_MESSAGES / 2)); + + // Verify that the remainder of the messages can be removed by empty + // selector. + Assert.assertEquals(NUM_MESSAGES - NUM_MESSAGES / 2, queue + .removeMatchingMessages("")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2571Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2571Test.java new file mode 100644 index 0000000000..533ae0c939 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2571Test.java @@ -0,0 +1,110 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; + +public class AMQ2571Test extends EmbeddedBrokerTestSupport { + + public void testTempQueueClosing() { + try { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(this.bindAddress); + connectionFactory.setAlwaysSyncSend(true); + + // First create session that will own the TempQueue + Connection connectionA = connectionFactory.createConnection(); + connectionA.start(); + + Session sessionA = connectionA.createSession(false, Session.AUTO_ACKNOWLEDGE); + + TemporaryQueue tempQueue = sessionA.createTemporaryQueue(); + + // Next, create session that will put messages on the queue. + Connection connectionB = connectionFactory.createConnection(); + connectionB.start(); + + Session sessionB = connectionB.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create a producer for connection B. + final MessageProducer producerB = sessionB.createProducer(tempQueue); + producerB.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + final TextMessage message = sessionB.createTextMessage("Testing AMQ TempQueue."); + + Thread sendingThread = new Thread(new Runnable() { + public void run() { + try { + long end = System.currentTimeMillis() + 5*60*1000; + // wait for exception on send + while (System.currentTimeMillis() < end) { + producerB.send(message); + } + } catch (JMSException e) { + e.printStackTrace(); + } + } + }); + + // Send 5000 messages. + sendingThread.start(); + // Now close connection A. This will remove the TempQueue. + connectionA.close(); + // Wait for the thread to finish. + sendingThread.join(5*60*1000); + + // Sleep for a while to make sure that we should know that the + // TempQueue is gone. + //Thread.sleep(50); + + // Now we test if we are able to send again. + try { + producerB.send(message); + fail("Involuntary recreated temporary queue."); + } catch (JMSException e) { + // Got exception, just as we wanted because the creator of + // the TempQueue had closed the connection prior to the send. + assertTrue("TempQueue does not exist anymore.", true); + } + } catch (Exception e) { + fail("Unexpected exception " + e); + } + } + + @Override + protected void setUp() throws Exception { + bindAddress = "vm://localhost"; + setAutoFail(true); + super.setUp(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.setUseJmx(false); + return answer; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2580Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2580Test.java new file mode 100644 index 0000000000..2bcb983b6a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2580Test.java @@ -0,0 +1,201 @@ +/** + * 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.bugs; + +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; + +public class AMQ2580Test extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2580Test.class); + + private static final String TOPIC_NAME = "topicName"; + private static final String CLIENT_ID = "client_id"; + private static final String textOfSelectedMsg = "good_message"; + + protected TopicConnection connection; + + private Topic topic; + private Session session; + private MessageProducer producer; + private ConnectionFactory connectionFactory; + private BrokerService service; + + public static Test suite() { + return suite(AMQ2580Test.class); + } + + protected void setUp() throws Exception { + super.setUp(); + initDurableBroker(); + initConnectionFactory(); + initTopic(); + } + + protected void tearDown() throws Exception { + shutdownClient(); + service.stop(); + super.tearDown(); + } + + private void initConnection() throws JMSException { + if (connection == null) { + LOG.info("Initializing connection"); + + connection = (TopicConnection) connectionFactory.createConnection(); + connection.start(); + } + } + + public void initCombosForTestTopicIsDurableSmokeTest() throws Exception { + addCombinationValues("defaultPersistenceAdapter", PersistenceAdapterChoice.values()); + } + + public void testTopicIsDurableSmokeTest() throws Exception { + + initClient(); + MessageConsumer consumer = createMessageConsumer(); + LOG.info("Consuming message"); + assertNull(consumer.receive(1)); + shutdownClient(); + consumer.close(); + + sendMessages(); + shutdownClient(); + + initClient(); + consumer = createMessageConsumer(); + + LOG.info("Consuming message"); + TextMessage answer1 = (TextMessage) consumer.receive(1000); + assertNotNull("we got our message", answer1); + + consumer.close(); + } + + private MessageConsumer createMessageConsumer() throws JMSException { + LOG.info("creating durable subscriber"); + return session.createDurableSubscriber(topic, + TOPIC_NAME, + "name='value'", + false); + } + + private void initClient() throws JMSException { + LOG.info("Initializing client"); + + initConnection(); + initSession(); + } + + private void shutdownClient() + throws JMSException { + LOG.info("Closing session and connection"); + session.close(); + connection.close(); + session = null; + connection = null; + } + + private void sendMessages() + throws JMSException { + initConnection(); + + initSession(); + + LOG.info("Creating producer"); + producer = session.createProducer(topic); + + sendMessageThatFailsSelection(); + + sendMessage(textOfSelectedMsg, "value"); + } + + private void initSession() throws JMSException { + LOG.info("Initializing session"); + session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + } + + private void sendMessageThatFailsSelection() throws JMSException { + for (int i = 0; i < 5; i++) { + String textOfNotSelectedMsg = "Msg_" + i; + sendMessage(textOfNotSelectedMsg, "not_value"); + LOG.info("#"); + } + } + + private void sendMessage( + String msgText, + String propertyValue) throws JMSException { + LOG.info("Creating message: " + msgText); + TextMessage messageToSelect = session.createTextMessage(msgText); + messageToSelect.setStringProperty("name", propertyValue); + LOG.info("Sending message"); + producer.send(messageToSelect); + } + + protected void initConnectionFactory() throws Exception { + ActiveMQConnectionFactory activeMqConnectionFactory = createActiveMqConnectionFactory(); + connectionFactory = activeMqConnectionFactory; + } + + + private ActiveMQConnectionFactory createActiveMqConnectionFactory() throws Exception { + ActiveMQConnectionFactory activeMqConnectionFactory = new ActiveMQConnectionFactory( + "failover:" + service.getTransportConnectors().get(0).getConnectUri().toString()); + activeMqConnectionFactory.setWatchTopicAdvisories(false); + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setDurableTopicPrefetch(2); + prefetchPolicy.setOptimizeDurableTopicPrefetch(2); + activeMqConnectionFactory.setPrefetchPolicy(prefetchPolicy); + activeMqConnectionFactory.setClientID(CLIENT_ID); + return activeMqConnectionFactory; + } + + private void initDurableBroker() throws Exception { + service = new BrokerService(); + setDefaultPersistenceAdapter(service); + service.setDeleteAllMessagesOnStartup(true); + service.setAdvisorySupport(false); + service.setTransportConnectorURIs(new String[]{"tcp://localhost:0"}); + service.setPersistent(true); + service.setUseJmx(false); + service.start(); + + } + + private void initTopic() throws JMSException { + initConnection(); + TopicSession topicSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + topic = topicSession.createTopic(TOPIC_NAME); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584ConcurrentDlqTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584ConcurrentDlqTest.java new file mode 100644 index 0000000000..3e41dc9a54 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584ConcurrentDlqTest.java @@ -0,0 +1,266 @@ +/** + * 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.bugs; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.Arrays; +import java.util.Properties; +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TopicSubscriber; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.IntrospectionSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// variation on AMQ2584 where the DLQ consumer works in parallel to producer so +// that some dups are not suppressed as they are already acked by the consumer +// the audit needs to be disabled to allow these dupes to be consumed +public class AMQ2584ConcurrentDlqTest extends org.apache.activemq.TestSupport { + + static final Logger LOG = LoggerFactory.getLogger(AMQ2584ConcurrentDlqTest.class); + BrokerService broker = null; + ActiveMQTopic topic; + + ActiveMQConnection consumerConnection = null, producerConnection = null, dlqConnection = null; + Session consumerSession; + Session producerSession; + MessageProducer producer; + Vector duralbeSubs = new Vector(); + final int numMessages = 1000; + final int numDurableSubs = 2; + + String data; + private long dlqConsumerLastReceivedTimeStamp; + private AtomicLong dlqReceivedCount = new AtomicLong(0); + + // 2 deliveries of each message, 3 producers + CountDownLatch redeliveryConsumerLatch = new CountDownLatch(((2 * numMessages) * numDurableSubs) - 1); + // should get at least numMessages, possibly more + CountDownLatch dlqConsumerLatch = new CountDownLatch((numMessages - 1)); + + public void testSize() throws Exception { + openConsumer(redeliveryConsumerLatch); + openDlqConsumer(dlqConsumerLatch); + + + assertEquals(0, broker.getAdminView().getStorePercentUsage()); + + for (int i = 0; i < numMessages; i++) { + sendMessage(false); + } + + final BrokerView brokerView = broker.getAdminView(); + + broker.getSystemUsage().getStoreUsage().isFull(); + LOG.info("store percent usage: " + brokerView.getStorePercentUsage()); + assertTrue("redelivery consumer got all it needs, remaining: " + + redeliveryConsumerLatch.getCount(), redeliveryConsumerLatch.await(60, TimeUnit.SECONDS)); + assertTrue("dql consumer got all it needs", dlqConsumerLatch.await(60, TimeUnit.SECONDS)); + closeConsumer(); + + LOG.info("Giving dlq a chance to clear down once topic consumer is closed"); + + // 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); + } + + private void openConsumer(final CountDownLatch latch) throws Exception { + consumerConnection = (ActiveMQConnection) createConnection(); + consumerConnection.setClientID("cliID"); + consumerConnection.start(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageListener listener = new MessageListener() { + public void onMessage(Message message) { + latch.countDown(); + try { + consumerSession.recover(); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + }; + + for (int i = 1; i <= numDurableSubs; i++) { + TopicSubscriber sub = consumerSession.createDurableSubscriber(topic, "subName" + i); + sub.setMessageListener(listener); + duralbeSubs.add(sub); + } + } + + private void openDlqConsumer(final CountDownLatch received) throws Exception { + + dlqConnection = (ActiveMQConnection) createConnection(); + Session dlqSession = dlqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer dlqConsumer = dlqSession.createConsumer(new ActiveMQQueue("ActiveMQ.DLQ")); + dlqConsumer.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + if (received.getCount() > 0 && received.getCount() % 200 == 0) { + LOG.info("remaining on DLQ: " + received.getCount()); + } + received.countDown(); + dlqConsumerLastReceivedTimeStamp = System.currentTimeMillis(); + dlqReceivedCount.incrementAndGet(); + } + }); + dlqConnection.start(); + } + + + private void closeConsumer() throws JMSException { + for (TopicSubscriber sub : duralbeSubs) { + sub.close(); + } + if (consumerSession != null) { + for (int i = 1; i <= numDurableSubs; i++) { + consumerSession.unsubscribe("subName" + i); + } + } + if (consumerConnection != null) { + consumerConnection.close(); + consumerConnection = null; + } + } + + private void closeDlqConsumer() throws JMSException, InterruptedException { + final long limit = System.currentTimeMillis() + 30 * 1000; + if (dlqConsumerLastReceivedTimeStamp > 0) { + while (System.currentTimeMillis() < dlqConsumerLastReceivedTimeStamp + 5000 + && System.currentTimeMillis() < limit) { + LOG.info("waiting for DLQ do drain, receivedCount: " + dlqReceivedCount); + TimeUnit.SECONDS.sleep(1); + } + } + if (dlqConnection != null) { + dlqConnection.close(); + dlqConnection = null; + } + } + + private void sendMessage(boolean filter) throws Exception { + if (producerConnection == null) { + producerConnection = (ActiveMQConnection) createConnection(); + producerConnection.start(); + producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = producerSession.createProducer(topic); + } + + Message message = producerSession.createMessage(); + message.setStringProperty("data", data); + producer.send(message); + } + + private void startBroker(boolean deleteMessages) throws Exception { + broker = new BrokerService(); + broker.setAdvisorySupport(false); + broker.setBrokerName("testStoreSize"); + + PolicyMap map = new PolicyMap(); + PolicyEntry entry = new PolicyEntry(); + entry.setEnableAudit(false); + map.setDefaultEntry(entry); + broker.setDestinationPolicy(map); + + if (deleteMessages) { + broker.setDeleteAllMessagesOnStartup(true); + } + configurePersistenceAdapter(broker.getPersistenceAdapter()); + broker.getSystemUsage().getStoreUsage().setLimit(200 * 1000 * 1000); + broker.start(); + } + + private void configurePersistenceAdapter(PersistenceAdapter persistenceAdapter) { + Properties properties = new Properties(); + String maxFileLengthVal = String.valueOf(2 * 1024 * 1024); + properties.put("journalMaxFileLength", maxFileLengthVal); + properties.put("maxFileLength", maxFileLengthVal); + properties.put("cleanupInterval", "2000"); + properties.put("checkpointInterval", "2000"); + // there are problems with duplicate dispatch in the cursor, which maintain + // a map of messages. A dup dispatch can be dropped. + // see: org.apache.activemq.broker.region.cursors.OrderedPendingList + // Adding duplicate detection to the default DLQ strategy removes the problem + // which means we can leave the default for concurrent store and dispatch q + //properties.put("concurrentStoreAndDispatchQueues", "false"); + + IntrospectionSupport.setProperties(persistenceAdapter, properties); + } + + private void stopBroker() throws Exception { + if (broker != null) + broker.stop(); + broker = null; + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://testStoreSize?jms.watchTopicAdvisories=false&jms.redeliveryPolicy.maximumRedeliveries=1&jms.redeliveryPolicy.initialRedeliveryDelay=0&waitForStart=5000&create=false"); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + StringBuilder sb = new StringBuilder(5000); + for (int i = 0; i < 5000; i++) { + sb.append('a'); + } + data = sb.toString(); + + startBroker(true); + topic = (ActiveMQTopic) createDestination(); + } + + @Override + protected void tearDown() throws Exception { + stopBroker(); + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584Test.java new file mode 100644 index 0000000000..b84b9abc93 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584Test.java @@ -0,0 +1,233 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class AMQ2584Test extends org.apache.activemq.TestSupport { + + static final Logger LOG = LoggerFactory.getLogger(AMQ2584Test.class); + BrokerService broker = null; + ActiveMQTopic topic; + + ActiveMQConnection consumerConnection = null, producerConnection = null; + Session producerSession; + MessageProducer producer; + final int minPercentUsageForStore = 3; + String data; + + private final TestSupport.PersistenceAdapterChoice persistenceAdapterChoice; + + @Parameterized.Parameters(name="{0}") + public static Collection getTestParameters() { + TestSupport.PersistenceAdapterChoice[] kahaDb = {TestSupport.PersistenceAdapterChoice.KahaDB}; + TestSupport.PersistenceAdapterChoice[] levelDb = {TestSupport.PersistenceAdapterChoice.LevelDB}; + List choices = new ArrayList(); + choices.add(kahaDb); + choices.add(levelDb); + + return choices; + } + + public AMQ2584Test(TestSupport.PersistenceAdapterChoice choice) { + this.persistenceAdapterChoice = choice; + } + + @Test(timeout = 120000) + public void testSize() throws Exception { + int messages = 1000; + CountDownLatch redeliveryConsumerLatch = new CountDownLatch((messages*3)); + openConsumer(redeliveryConsumerLatch); + + assertEquals(0, broker.getAdminView().getStorePercentUsage()); + + for (int i = 0; i < messages; i++) { + sendMessage(false); + } + + final BrokerView brokerView = broker.getAdminView(); + + broker.getSystemUsage().getStoreUsage().isFull(); + LOG.info("store percent usage: "+brokerView.getStorePercentUsage()); + int storePercentUsage = broker.getAdminView().getStorePercentUsage(); + assertTrue("some store in use", storePercentUsage > minPercentUsageForStore); + + assertTrue("redelivery consumer got all it needs", redeliveryConsumerLatch.await(60, TimeUnit.SECONDS)); + closeConsumer(); + + // consume from DLQ + final CountDownLatch received = new CountDownLatch(messages); + consumerConnection = (ActiveMQConnection) createConnection(); + Session dlqSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer dlqConsumer = dlqSession.createConsumer(new ActiveMQQueue("ActiveMQ.DLQ")); + dlqConsumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + if (received.getCount() % 500 == 0) { + LOG.info("remaining on DLQ: " + received.getCount()); + } + received.countDown(); + } + }); + consumerConnection.start(); + + assertTrue("Not all messages reached the DLQ", received.await(60, TimeUnit.SECONDS)); + + assertTrue("Store usage exceeds expected usage", + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + broker.getSystemUsage().getStoreUsage().isFull(); + LOG.info("store precent usage: "+brokerView.getStorePercentUsage()); + return broker.getAdminView().getStorePercentUsage() < minPercentUsageForStore; + } + })); + + closeConsumer(); + + } + + private void openConsumer(final CountDownLatch latch) throws Exception { + consumerConnection = (ActiveMQConnection) createConnection(); + consumerConnection.setClientID("cliID"); + consumerConnection.start(); + final Session session = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageListener listener = new MessageListener() { + @Override + public void onMessage(Message message) { + latch.countDown(); + try { + session.recover(); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + + } + }; + + session.createDurableSubscriber(topic, "subName1").setMessageListener(listener); + session.createDurableSubscriber(topic, "subName2").setMessageListener(listener); + session.createDurableSubscriber(topic, "subName3").setMessageListener(listener); + } + + private void closeConsumer() throws JMSException { + if (consumerConnection != null) + consumerConnection.close(); + consumerConnection = null; + } + + private void sendMessage(boolean filter) throws Exception { + if (producerConnection == null) { + producerConnection = (ActiveMQConnection) createConnection(); + producerConnection.start(); + producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = producerSession.createProducer(topic); + } + + Message message = producerSession.createMessage(); + message.setStringProperty("data", data); + producer.send(message); + } + + private void startBroker(boolean deleteMessages) throws Exception { + broker = new BrokerService(); + broker.setAdvisorySupport(false); + broker.setBrokerName("testStoreSize"); + + if (deleteMessages) { + broker.setDeleteAllMessagesOnStartup(true); + } + LOG.info("Starting broker with persistenceAdapterChoice " + persistenceAdapterChoice.toString()); + setPersistenceAdapter(broker, persistenceAdapterChoice); + configurePersistenceAdapter(broker.getPersistenceAdapter()); + broker.getSystemUsage().getStoreUsage().setLimit(200 * 1000 * 1000); + broker.start(); + } + + private void configurePersistenceAdapter(PersistenceAdapter persistenceAdapter) { + Properties properties = new Properties(); + String maxFileLengthVal = String.valueOf(1 * 1024 * 1024); + properties.put("journalMaxFileLength", maxFileLengthVal); + properties.put("maxFileLength", maxFileLengthVal); + properties.put("cleanupInterval", "2000"); + properties.put("checkpointInterval", "2000"); + + IntrospectionSupport.setProperties(persistenceAdapter, properties); + } + + private void stopBroker() throws Exception { + if (broker != null) + broker.stop(); + broker = null; + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://testStoreSize?jms.watchTopicAdvisories=false&jms.redeliveryPolicy.maximumRedeliveries=0&jms.closeTimeout=60000&waitForStart=5000&create=false"); + } + + @Override + @Before + public void setUp() throws Exception { + StringBuilder sb = new StringBuilder(5000); + for (int i = 0; i < 5000; i++) { + sb.append('a'); + } + data = sb.toString(); + + startBroker(true); + topic = (ActiveMQTopic) createDestination(); + } + + @Override + @After + public void tearDown() throws Exception { + stopBroker(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2585Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2585Test.java new file mode 100644 index 0000000000..3f515d9031 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2585Test.java @@ -0,0 +1,83 @@ +/** + * + * 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.bugs; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.EmbeddedBrokerAndConnectionTestSupport; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.Message; +import org.apache.activemq.spring.ConsumerBean; + +public class AMQ2585Test extends EmbeddedBrokerAndConnectionTestSupport { + private final Destination destination = new ActiveMQQueue("MyQueue"); + final static String LENGTH10STRING = "1234567890"; + private Session session; + private MessageProducer producer; + private ConsumerBean messageList; + + public void testOneMessageWithProperties() throws Exception { + TextMessage message = session.createTextMessage(LENGTH10STRING); + message.setStringProperty(LENGTH10STRING, LENGTH10STRING); + producer.send(message); + + messageList.assertMessagesArrived(1); + + ActiveMQTextMessage received = ((ActiveMQTextMessage) messageList + .flushMessages().get(0)); + + assertEquals(LENGTH10STRING, received.getText()); + assertTrue(received.getProperties().size() > 0); + assertTrue(received.propertyExists(LENGTH10STRING)); + assertEquals(LENGTH10STRING, received.getStringProperty(LENGTH10STRING)); + + /** + * As specified by getSize(), the size (memory usage) of the body should + * be length of text * 2. Unsure of how memory usage is calculated for + * properties, but should probably not be less than the sum of (string) + * lengths for the key name and value. + */ + + final int sizeShouldBeNoLessThan = LENGTH10STRING.length() * 4 + Message.DEFAULT_MINIMUM_MESSAGE_SIZE; + assertTrue("Message size was smaller than expected: " + received.getSize(), + received.getSize() >= sizeShouldBeNoLessThan); + assertFalse(LENGTH10STRING.length() * 2 == received.getSize()); + } + + @Override + protected void setUp() throws Exception { + bindAddress = bindAddress + "?marshal=true"; + super.setUp(); + messageList = new ConsumerBean(); + messageList.setVerbose(true); + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer messageConsumer = session.createConsumer(destination); + + messageConsumer.setMessageListener(messageList); + + producer = session.createProducer(destination); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2616Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2616Test.java new file mode 100644 index 0000000000..4f6f16816e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2616Test.java @@ -0,0 +1,116 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.IOHelper; + +public class AMQ2616Test extends TestCase { + private static final int NUMBER = 2000; + private BrokerService brokerService; + private final ArrayList threads = new ArrayList(); + private final String ACTIVEMQ_BROKER_BIND = "tcp://0.0.0.0:0"; + private final AtomicBoolean shutdown = new AtomicBoolean(); + + private String connectionUri; + + public void testQueueResourcesReleased() throws Exception{ + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(connectionUri); + Connection tempConnection = fac.createConnection(); + tempConnection.start(); + Session tempSession = tempConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue tempQueue = tempSession.createTemporaryQueue(); + + Connection testConnection = fac.createConnection(); + long startUsage = brokerService.getSystemUsage().getMemoryUsage().getUsage(); + Session testSession = testConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer testProducer = testSession.createProducer(tempQueue); + byte[] payload = new byte[1024*4]; + for (int i = 0; i < NUMBER; i++ ) { + BytesMessage msg = testSession.createBytesMessage(); + msg.writeBytes(payload); + testProducer.send(msg); + } + long endUsage = brokerService.getSystemUsage().getMemoryUsage().getUsage(); + assertFalse(startUsage==endUsage); + tempConnection.close(); + Thread.sleep(1000); + endUsage = brokerService.getSystemUsage().getMemoryUsage().getUsage(); + assertEquals(startUsage,endUsage); + } + + + @Override + protected void setUp() throws Exception { + // Start an embedded broker up. + brokerService = new BrokerService(); + + KahaDBPersistenceAdapter adaptor = new KahaDBPersistenceAdapter(); + adaptor.setEnableJournalDiskSyncs(false); + File file = new File("target/AMQ2616Test"); + IOHelper.mkdirs(file); + IOHelper.deleteChildren(file); + adaptor.setDirectory(file); + brokerService.setPersistenceAdapter(adaptor); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry pe = new PolicyEntry(); + pe.setMemoryLimit(10 * 1024 * 1024); + pe.setOptimizedDispatch(true); + pe.setProducerFlowControl(false); + pe.setExpireMessagesPeriod(1000); + pe.setPendingQueuePolicy(new FilePendingQueueMessageStoragePolicy()); + policyMap.put(new ActiveMQQueue(">"), pe); + brokerService.setDestinationPolicy(policyMap); + brokerService.getSystemUsage().getMemoryUsage().setLimit(20 * 1024 * 1024); + brokerService.getSystemUsage().getTempUsage().setLimit(200 * 1024 * 1024); + brokerService.addConnector(ACTIVEMQ_BROKER_BIND); + brokerService.start(); + brokerService.waitUntilStarted(); + + connectionUri = brokerService.getTransportConnectors().get(0).getPublishableConnectString(); + + new ActiveMQQueue(getName()); + } + + @Override + protected void tearDown() throws Exception { + // Stop any running threads. + shutdown.set(true); + for (Thread t : threads) { + t.interrupt(); + t.join(); + } + brokerService.stop(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2645Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2645Test.java new file mode 100644 index 0000000000..2ac6ff3f37 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2645Test.java @@ -0,0 +1,109 @@ +/** + * 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.bugs; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2645Test extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(AMQ2645Test.class); + private final static String QUEUE_NAME = "test.daroo.q"; + + public void testWaitForTransportInterruptionProcessingHang() + throws Exception { + final ConnectionFactory fac = new ActiveMQConnectionFactory( + "failover:(" + this.bindAddress + ")"); + final Connection connection = fac.createConnection(); + try { + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue queue = session.createQueue(QUEUE_NAME); + final MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + producer.send(session.createTextMessage("test")); + + final CountDownLatch afterRestart = new CountDownLatch(1); + final CountDownLatch twoNewMessages = new CountDownLatch(1); + final CountDownLatch thirdMessageReceived = new CountDownLatch(1); + + final MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + try { + afterRestart.await(); + + final TextMessage txtMsg = (TextMessage) message; + if (txtMsg.getText().equals("test")) { + producer.send(session.createTextMessage("test 1")); + TimeUnit.SECONDS.sleep(5); + // THIS SECOND send() WILL CAUSE CONSUMER DEADLOCK + producer.send(session.createTextMessage("test 2")); + LOG.info("Two new messages produced."); + twoNewMessages.countDown(); + } else if (txtMsg.getText().equals("test 3")) { + thirdMessageReceived.countDown(); + } + } catch (Exception e) { + LOG.error(e.toString()); + throw new RuntimeException(e); + } + } + }); + + LOG.info("Stopping broker...."); + broker.stop(); + + LOG.info("Creating new broker..."); + broker = createBroker(); + startBroker(); + broker.waitUntilStarted(); + + afterRestart.countDown(); + assertTrue("Consumer is deadlocked!", twoNewMessages.await(60, TimeUnit.SECONDS)); + + producer.send(session.createTextMessage("test 3")); + assertTrue("Consumer got third message after block", thirdMessageReceived.await(60, TimeUnit.SECONDS)); + + } finally { + broker.stop(); + } + + } + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://0.0.0.0:61617"; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2736Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2736Test.java new file mode 100644 index 0000000000..e5845725ad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2736Test.java @@ -0,0 +1,96 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.DefaultIOExceptionHandler; +import org.junit.After; +import org.junit.Test; + + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class AMQ2736Test { + BrokerService broker; + + @Test + public void testRollbackOnRecover() throws Exception { + broker = createAndStartBroker(true); + DefaultIOExceptionHandler ignoreAllExceptionsIOExHandler = new DefaultIOExceptionHandler(); + ignoreAllExceptionsIOExHandler.setIgnoreAllErrors(true); + broker.setIoExceptionHandler(ignoreAllExceptionsIOExHandler); + + ActiveMQConnectionFactory f = new ActiveMQConnectionFactory("vm://localhost?async=false"); + f.setAlwaysSyncSend(true); + Connection c = f.createConnection(); + c.start(); + Session s = c.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer p = s.createProducer(new ActiveMQQueue("Tx")); + p.send(s.createTextMessage("aa")); + + // kill journal without commit + KahaDBPersistenceAdapter pa = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + KahaDBStore store = pa.getStore(); + + assertNotNull("last tx location is present " + store.getInProgressTxLocationRange()[1]); + + // test hack, close the journal to ensure no further journal updates when broker stops + // mimic kill -9 in terms of no normal shutdown sequence + store.getJournal().close(); + try { + store.close(); + } catch (Exception expectedLotsAsJournalBorked) { + } + + broker.stop(); + broker.waitUntilStopped(); + + // restart with recovery + broker = createAndStartBroker(false); + + pa = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + store = pa.getStore(); + + // inflight non xa tx should be rolledback on recovery + assertNull("in progress tx location is present ", store.getInProgressTxLocationRange()[0]); + + } + + @After + public void stopBroker() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + private BrokerService createAndStartBroker(boolean deleteAll) throws Exception { + BrokerService broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(deleteAll); + broker.setUseJmx(false); + broker.getManagementContext().setCreateConnector(false); + broker.start(); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2751Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2751Test.java new file mode 100644 index 0000000000..b52f5c0dac --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2751Test.java @@ -0,0 +1,94 @@ +/** + * 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.bugs; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2751Test extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(AMQ2751Test.class); + + private static String clientIdPrefix = "consumer"; + private static String queueName = "FOO"; + + public void testRecoverRedelivery() throws Exception { + + final CountDownLatch redelivery = new CountDownLatch(6); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + "failover:(" + broker.getTransportConnectors().get(0).getConnectUri() + ")"); + try { + + Connection connection = factory.createConnection(); + String clientId = clientIdPrefix; + connection.setClientID(clientId); + + final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + Queue queue = session.createQueue(queueName); + + MessageConsumer consumer = session.createConsumer(queue); + + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + try { + LOG.info("Got message: " + message.getJMSMessageID()); + if (message.getJMSRedelivered()) { + LOG.info("It's a redelivery."); + redelivery.countDown(); + } + LOG.info("calling recover() on the session to force redelivery."); + session.recover(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + }); + + System.out.println("Created queue consumer with clientId " + clientId); + connection.start(); + + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage("test")); + + assertTrue("we got 6 redeliveries", redelivery.await(20, TimeUnit.SECONDS)); + + } finally { + broker.stop(); + } + + } + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2801Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2801Test.java new file mode 100644 index 0000000000..a1d0bc1cdf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2801Test.java @@ -0,0 +1,201 @@ +/** + * 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.bugs; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.DurableSubscriptionViewMBean; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.usage.SystemUsage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2801Test +{ + private static final Logger LOG = LoggerFactory.getLogger(AMQ2801Test.class); + + private static final String TOPICNAME = "InvalidPendingQueueTest"; + private static final String SELECTOR1 = "JMS_ID" + " = '" + "TEST" + "'"; + private static final String SELECTOR2 = "JMS_ID" + " = '" + "TEST2" + "'"; + private static final String SUBSCRIPTION1 = "InvalidPendingQueueTest_1"; + private static final String SUBSCRIPTION2 = "InvalidPendingQueueTest_2"; + private static final int MSG_COUNT = 2500; + private Session session1; + private Connection conn1; + private Topic topic1; + private MessageConsumer consumer1; + private Session session2; + private Connection conn2; + private Topic topic2; + private MessageConsumer consumer2; + private BrokerService broker; + private String connectionUri; + + @Before + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector("tcp://localhost:0").setName("Default"); + applyMemoryLimitPolicy(broker); + broker.start(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + private void applyMemoryLimitPolicy(BrokerService broker) { + final SystemUsage memoryManager = new SystemUsage(); + memoryManager.getMemoryUsage().setLimit(5818230784L); + memoryManager.getStoreUsage().setLimit(6442450944L); + memoryManager.getTempUsage().setLimit(3221225472L); + broker.setSystemUsage(memoryManager); + + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setQueue(">"); + entry.setProducerFlowControl(false); + entry.setMemoryLimit(504857608); + entry.setPendingQueuePolicy(new FilePendingQueueMessageStoragePolicy()); + policyEntries.add(entry); + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + broker.setDestinationPolicy(policyMap); + } + + @After + public void tearDown() throws Exception { + conn1.close(); + conn2.close(); + if (broker != null) { + broker.stop(); + } + } + + private void produceMessages() throws Exception { + TopicConnection connection = createConnection(); + TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic(TOPICNAME); + TopicPublisher producer = session.createPublisher(topic); + connection.start(); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + long tStamp = System.currentTimeMillis(); + BytesMessage message = session2.createBytesMessage(); + for (int i = 1; i <= MSG_COUNT; i++) + { + message.setStringProperty("JMS_ID", "TEST"); + message.setIntProperty("Type", i); + producer.publish(message); + if (i%100 == 0) { + LOG.info("sent: " + i + " @ " + ((System.currentTimeMillis() - tStamp) / 100) + "m/ms"); + tStamp = System.currentTimeMillis() ; + } + } + } + + private void activeateSubscribers() throws Exception { + // First consumer + conn1 = createConnection(); + conn1.setClientID(SUBSCRIPTION1); + session1 = conn1.createSession(true, Session.SESSION_TRANSACTED); + topic1 = session1.createTopic(TOPICNAME); + consumer1 = session1.createDurableSubscriber(topic1, SUBSCRIPTION1, SELECTOR1, false); + conn1.start(); + + // Second consumer that just exists + conn2 = createConnection(); + conn2.setClientID(SUBSCRIPTION2); + session2 = conn2.createSession(true, Session.SESSION_TRANSACTED); + topic2 = session2.createTopic(TOPICNAME); + consumer2 = session2.createDurableSubscriber(topic2, SUBSCRIPTION2, SELECTOR2, false); + conn2.start(); + } + + @Test + public void testInvalidPendingQueue() throws Exception { + + activeateSubscribers(); + + assertNotNull(consumer1); + assertNotNull(consumer2); + + produceMessages(); + LOG.debug("Sent messages to a single subscriber"); + Thread.sleep(2000); + + LOG.debug("Closing durable subscriber connections"); + conn1.close(); + conn2.close(); + LOG.debug("Closed durable subscriber connections"); + + Thread.sleep(2000); + LOG.debug("Re-starting durable subscriber connections"); + + activeateSubscribers(); + LOG.debug("Started up durable subscriber connections - now view activemq console to see pending queue size on the other subscriber"); + + ObjectName[] subs = broker.getAdminView().getDurableTopicSubscribers(); + + for (int i = 0; i < subs.length; i++) { + ObjectName subName = subs[i]; + DurableSubscriptionViewMBean sub = (DurableSubscriptionViewMBean) + broker.getManagementContext().newProxyInstance(subName, DurableSubscriptionViewMBean.class, true); + + LOG.info(sub.getSubscriptionName() + ": pending = " + sub.getPendingQueueSize() + ", dispatched: " + sub.getDispatchedQueueSize()); + if(sub.getSubscriptionName().equals(SUBSCRIPTION1)) { + assertEquals("Incorrect number of pending messages", MSG_COUNT, sub.getPendingQueueSize() + sub.getDispatchedQueueSize()); + } else { + assertEquals("Incorrect number of pending messages", 0, sub.getPendingQueueSize()); + } + } + } + + private TopicConnection createConnection() throws Exception + { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); + connectionFactory.setBrokerURL(connectionUri); + TopicConnection conn = connectionFactory.createTopicConnection(); + return conn; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2832Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2832Test.java new file mode 100644 index 0000000000..22ad6abd4c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2832Test.java @@ -0,0 +1,380 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.disk.journal.DataFile; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ2832Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2832Test.class); + + BrokerService broker = null; + private ActiveMQConnectionFactory cf; + private final Destination destination = new ActiveMQQueue("AMQ2832Test"); + private String connectionUri; + + protected void startBroker() throws Exception { + doStartBroker(true, false); + } + + protected void restartBroker() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + doStartBroker(false, false); + } + + protected void recoverBroker() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + doStartBroker(false, true); + } + + private void doStartBroker(boolean delete, boolean recover) throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(delete); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.addConnector("tcp://localhost:0"); + + configurePersistence(broker, recover); + + connectionUri = "vm://localhost?create=false"; + cf = new ActiveMQConnectionFactory(connectionUri); + + broker.start(); + LOG.info("Starting broker.."); + } + + protected void configurePersistence(BrokerService brokerService, boolean recover) throws Exception { + KahaDBPersistenceAdapter adapter = (KahaDBPersistenceAdapter) brokerService.getPersistenceAdapter(); + + // ensure there are a bunch of data files but multiple entries in each + adapter.setJournalMaxFileLength(1024 * 20); + + // speed up the test case, checkpoint an cleanup early and often + adapter.setCheckpointInterval(5000); + adapter.setCleanupInterval(5000); + + if (recover) { + adapter.setForceRecoverIndex(true); + } + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + /** + * Scenario: + * db-1.log has an unacknowledged message, + * db-2.log contains acks for the messages from db-1.log, + * db-3.log contains acks for the messages from db-2.log + * + * Expected behavior: since db-1.log is blocked, db-2.log and db-3.log should not be removed during the cleanup. + * Current situation on 5.10.0, 5.10.1 is that db-3.log is removed causing all messages from db-2.log, whose acks were in db-3.log, to be replayed. + * + * @throws Exception + */ + @Test + public void testAckChain() throws Exception { + startBroker(); + + StagedConsumer consumer = new StagedConsumer(); + // file #1 + produceMessagesToConsumeMultipleDataFiles(5); + // acknowledge first 2 messages and leave the 3rd one unacknowledged blocking db-1.log + consumer.receive(3); + + // send messages by consuming and acknowledging every message right after sent in order to get KahadbAdd and Remove command to be saved together + // this is necessary in order to get KahaAddMessageCommand to be saved in one db file and the corresponding KahaRemoveMessageCommand in the next one + produceAndConsumeImmediately(20, consumer); + consumer.receive(2).acknowledge(); // consume and ack the last 2 unconsumed + + // now we have 3 files written and started with #4 + consumer.close(); + + broker.stop(); + broker.waitUntilStopped(); + + recoverBroker(); + + consumer = new StagedConsumer(); + Message message = consumer.receive(1); + assertNotNull("One message stays unacked from db-1.log", message); + message.acknowledge(); + message = consumer.receive(1); + assertNull("There should not be any unconsumed messages any more", message); + consumer.close(); + } + + private void produceAndConsumeImmediately(int numOfMsgs, StagedConsumer consumer) throws Exception { + for (int i = 0; i < numOfMsgs; i++) { + produceMessagesToConsumeMultipleDataFiles(1); + consumer.receive(1).acknowledge(); + } + } + + @Test + public void testAckRemovedMessageReplayedAfterRecovery() throws Exception { + + startBroker(); + + StagedConsumer consumer = new StagedConsumer(); + int numMessagesAvailable = produceMessagesToConsumeMultipleDataFiles(20); + // this will block the reclaiming of one data file + Message firstUnacked = consumer.receive(10); + LOG.info("first unacked: " + firstUnacked.getJMSMessageID()); + Message secondUnacked = consumer.receive(1); + LOG.info("second unacked: " + secondUnacked.getJMSMessageID()); + numMessagesAvailable -= 11; + + numMessagesAvailable += produceMessagesToConsumeMultipleDataFiles(10); + // ensure ack is another data file + LOG.info("Acking firstUnacked: " + firstUnacked.getJMSMessageID()); + firstUnacked.acknowledge(); + + numMessagesAvailable += produceMessagesToConsumeMultipleDataFiles(10); + + consumer.receive(numMessagesAvailable).acknowledge(); + + // second unacked should keep first data file available but journal with the first ack + // may get whacked + consumer.close(); + + broker.stop(); + broker.waitUntilStopped(); + + recoverBroker(); + + consumer = new StagedConsumer(); + // need to force recovery? + + Message msg = consumer.receive(1, 5); + assertNotNull("One messages left after recovery", msg); + msg.acknowledge(); + + // should be no more messages + msg = consumer.receive(1, 5); + assertEquals("Only one messages left after recovery: " + msg, null, msg); + consumer.close(); + } + + @Test + public void testAlternateLossScenario() throws Exception { + + startBroker(); + PersistenceAdapter pa = broker.getPersistenceAdapter(); + if (pa instanceof LevelDBStore) { + return; + } + + ActiveMQQueue queue = new ActiveMQQueue("MyQueue"); + ActiveMQQueue disposable = new ActiveMQQueue("MyDisposableQueue"); + ActiveMQTopic topic = new ActiveMQTopic("MyDurableTopic"); + + // This ensure that data file 1 never goes away. + createInactiveDurableSub(topic); + assertEquals(1, getNumberOfJournalFiles()); + + // One Queue Message that will be acked in another data file. + produceMessages(queue, 1); + assertEquals(1, getNumberOfJournalFiles()); + + // Add some messages to consume space + produceMessages(disposable, 50); + + int dataFilesCount = getNumberOfJournalFiles(); + assertTrue(dataFilesCount > 1); + + // Create an ack for the single message on this queue + drainQueue(queue); + + // Add some more messages to consume space beyond tha data file with the ack + produceMessages(disposable, 50); + + assertTrue(dataFilesCount < getNumberOfJournalFiles()); + dataFilesCount = getNumberOfJournalFiles(); + + restartBroker(); + + // Clear out all queue data + broker.getAdminView().removeQueue(disposable.getQueueName()); + + // Once this becomes true our ack could be lost. + assertTrue("Less than three journal file expected, was " + getNumberOfJournalFiles(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return getNumberOfJournalFiles() <= 3; + } + }, TimeUnit.MINUTES.toMillis(3))); + + // Recover and the Message should not be replayed but if the old MessageAck is lost + // then it could be. + recoverBroker(); + + assertTrue(drainQueue(queue) == 0); + } + + private int getNumberOfJournalFiles() throws IOException { + + Collection files = + ((KahaDBPersistenceAdapter) broker.getPersistenceAdapter()).getStore().getJournal().getFileMap().values(); + int reality = 0; + for (DataFile file : files) { + if (file != null) { + reality++; + } + } + + return reality; + } + + private void createInactiveDurableSub(Topic topic) throws Exception { + Connection connection = cf.createConnection(); + connection.setClientID("Inactive"); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "Inactive"); + consumer.close(); + connection.close(); + produceMessages(topic, 1); + } + + private int drainQueue(Queue queue) throws Exception { + Connection connection = cf.createConnection(); + connection.setClientID("Inactive"); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + int count = 0; + while (consumer.receive(5000) != null) { + count++; + } + consumer.close(); + connection.close(); + return count; + } + + private int produceMessages(Destination destination, int numToSend) throws Exception { + int sent = 0; + Connection connection = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getConnectUri()).createConnection(); + connection.start(); + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < numToSend; i++) { + producer.send(createMessage(session, i)); + sent++; + } + } finally { + connection.close(); + } + + return sent; + } + + private int produceMessagesToConsumeMultipleDataFiles(int numToSend) throws Exception { + return produceMessages(destination, numToSend); + } + + final String payload = new String(new byte[1024]); + + private Message createMessage(Session session, int i) throws Exception { + return session.createTextMessage(payload + "::" + i); + } + + private class StagedConsumer { + Connection connection; + MessageConsumer consumer; + + StagedConsumer() throws Exception { + connection = new ActiveMQConnectionFactory("failover://" + + broker.getTransportConnectors().get(0).getConnectUri().toString()).createConnection(); + connection.start(); + consumer = connection.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE).createConsumer(destination); + } + + public Message receive(int numToReceive) throws Exception { + return receive(numToReceive, 2); + } + + public Message receive(int numToReceive, int timeoutInSeconds) throws Exception { + Message msg = null; + for (; numToReceive > 0; numToReceive--) { + + do { + msg = consumer.receive(1*1000); + } while (msg == null && --timeoutInSeconds > 0); + + if (numToReceive > 1) { + msg.acknowledge(); + } + + if (msg != null) { + LOG.debug("received: " + msg.getJMSMessageID()); + } + } + // last message, unacked + return msg; + } + + void close() throws JMSException { + consumer.close(); + connection.close(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2870Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2870Test.java new file mode 100644 index 0000000000..8bb6bff7ec --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2870Test.java @@ -0,0 +1,230 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Properties; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class AMQ2870Test extends org.apache.activemq.TestSupport { + + static final Logger LOG = LoggerFactory.getLogger(AMQ2870Test.class); + BrokerService broker = null; + ActiveMQTopic topic; + + ActiveMQConnection consumerConnection = null, producerConnection = null; + Session producerSession; + MessageProducer producer; + final int minPercentUsageForStore = 10; + String data; + + private final PersistenceAdapterChoice persistenceAdapterChoice; + + @Parameterized.Parameters + public static Collection getTestParameters() { + String osName = System.getProperty("os.name"); + LOG.info("Running on [" + osName + "]"); + PersistenceAdapterChoice[] kahaDb = {PersistenceAdapterChoice.KahaDB}; + PersistenceAdapterChoice[] levelDb = {PersistenceAdapterChoice.LevelDB}; + List choices = new ArrayList(); + choices.add(kahaDb); + if (!osName.equalsIgnoreCase("AIX") && !osName.equalsIgnoreCase("SunOS")) { + choices.add(levelDb); + } + + return choices; + } + + public AMQ2870Test(PersistenceAdapterChoice choice) { + this.persistenceAdapterChoice = choice; + } + + @Test(timeout = 300000) + public void testSize() throws Exception { + openConsumer(); + + assertEquals(0, broker.getAdminView().getStorePercentUsage()); + + for (int i = 0; i < 5000; i++) { + sendMessage(false); + } + + final BrokerView brokerView = broker.getAdminView(); + + // wait for reclaim + assertTrue("in range with consumer", + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + // usage percent updated only on send check for isFull so once + // sends complete it is no longer updated till next send via a call to isFull + // this is optimal as it is only used to block producers + broker.getSystemUsage().getStoreUsage().isFull(); + LOG.info("store percent usage: "+brokerView.getStorePercentUsage()); + return broker.getAdminView().getStorePercentUsage() < minPercentUsageForStore; + } + })); + + closeConsumer(); + + assertTrue("in range with closed consumer", + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + broker.getSystemUsage().getStoreUsage().isFull(); + LOG.info("store precent usage: "+brokerView.getStorePercentUsage()); + return broker.getAdminView().getStorePercentUsage() < minPercentUsageForStore; + } + })); + + for (int i = 0; i < 5000; i++) { + sendMessage(false); + } + + // What if i drop the subscription? + broker.getAdminView().destroyDurableSubscriber("cliID", "subName"); + + assertTrue("in range after send with consumer", + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + broker.getSystemUsage().getStoreUsage().isFull(); + LOG.info("store precent usage: "+brokerView.getStorePercentUsage()); + return broker.getAdminView().getStorePercentUsage() < minPercentUsageForStore; + } + })); + } + + private void openConsumer() throws Exception { + consumerConnection = (ActiveMQConnection) createConnection(); + consumerConnection.setClientID("cliID"); + consumerConnection.start(); + Session session = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber subscriber = session.createDurableSubscriber(topic, "subName", "filter=true", false); + + subscriber.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + // received++; + } + }); + } + + private void closeConsumer() throws JMSException { + if (consumerConnection != null) + consumerConnection.close(); + consumerConnection = null; + } + + private void sendMessage(boolean filter) throws Exception { + if (producerConnection == null) { + producerConnection = (ActiveMQConnection) createConnection(); + producerConnection.start(); + producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = producerSession.createProducer(topic); + } + + Message message = producerSession.createMessage(); + message.setBooleanProperty("filter", filter); + message.setStringProperty("data", data); + producer.send(message); + } + + private void startBroker(boolean deleteMessages) throws Exception { + broker = new BrokerService(); + broker.setAdvisorySupport(false); + broker.setBrokerName("testStoreSize"); + + if (deleteMessages) { + broker.setDeleteAllMessagesOnStartup(true); + } + LOG.info("Starting broker with persistenceAdapterChoice " + persistenceAdapterChoice.toString()); + setPersistenceAdapter(broker, persistenceAdapterChoice); + configurePersistenceAdapter(broker.getPersistenceAdapter()); + broker.getSystemUsage().getStoreUsage().setLimit(100 * 1000 * 1000); + broker.start(); + } + + private void configurePersistenceAdapter(PersistenceAdapter persistenceAdapter) { + Properties properties = new Properties(); + String maxFileLengthVal = String.valueOf(2 * 1024 * 1024); + properties.put("journalMaxFileLength", maxFileLengthVal); + properties.put("maxFileLength", maxFileLengthVal); + properties.put("cleanupInterval", "2000"); + properties.put("checkpointInterval", "2000"); + + // leveldb + properties.put("logSize", maxFileLengthVal); + + IntrospectionSupport.setProperties(persistenceAdapter, properties); + } + + private void stopBroker() throws Exception { + if (broker != null) + broker.stop(); + broker = null; + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://testStoreSize?jms.watchTopicAdvisories=false&waitForStart=5000&create=false"); + } + + @Override + @Before + public void setUp() throws Exception { + StringBuilder sb = new StringBuilder(5000); + for (int i = 0; i < 5000; i++) { + sb.append('a'); + } + data = sb.toString(); + + startBroker(true); + topic = (ActiveMQTopic) createDestination(); + } + + @Override + @After + public void tearDown() throws Exception { + stopBroker(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2902Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2902Test.java new file mode 100644 index 0000000000..3c38186f8b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2902Test.java @@ -0,0 +1,98 @@ +/** + * 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.bugs; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.TransportConnection; +import org.apache.activemq.transport.TransportDisposedIOException; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; +import org.slf4j.LoggerFactory; + +public class AMQ2902Test extends TestCase { + private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AMQ2580Test.class); + + final AtomicBoolean gotExceptionInLog = new AtomicBoolean(Boolean.FALSE); + final AtomicBoolean failedToFindMDC = new AtomicBoolean(Boolean.FALSE); + + Appender appender = new DefaultTestAppender() { + @Override + public void doAppend(LoggingEvent event) { + if (event.getThrowableInformation() != null + && event.getThrowableInformation().getThrowable() instanceof TransportDisposedIOException) { + + // Prevent StackOverflowException so we can see a sane stack trace. + if (gotExceptionInLog.get()) { + return; + } + + gotExceptionInLog.set(Boolean.TRUE); + LOG.error("got event: " + event + ", ex:" + event.getThrowableInformation().getThrowable(), event.getThrowableInformation().getThrowable()); + LOG.error("Event source: ", new Throwable("Here")); + } + if( !"Loaded the Bouncy Castle security provider.".equals(event.getMessage()) ) { + if (event.getMDC("activemq.broker") == null) { + failedToFindMDC.set(Boolean.TRUE); + } + } + return; + } + }; + + public void testNoExceptionOnClosewithStartStop() throws JMSException { + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( + "vm://localhost?broker.persistent=false"); + Connection connection = connectionFactory.createConnection(); + connection.start(); + connection.stop(); + connection.close(); + } + + public void testNoExceptionOnClose() throws JMSException { + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( + "vm://localhost?broker.persistent=false"); + Connection connection = connectionFactory.createConnection(); + connection.close(); + } + + @Override + public void setUp() throws Exception { + gotExceptionInLog.set(Boolean.FALSE); + failedToFindMDC.set(Boolean.FALSE); + Logger.getRootLogger().addAppender(appender); + Logger.getLogger(TransportConnection.class.getName() + ".Transport").setLevel(Level.DEBUG); + Logger.getLogger(TransportConnection.class.getName()).setLevel(Level.DEBUG); + } + + @Override + public void tearDown() throws Exception { + Logger.getRootLogger().removeAppender(appender); + assertFalse("got unexpected ex in log on graceful close", gotExceptionInLog.get()); + assertFalse("MDC is there", failedToFindMDC.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2910Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2910Test.java new file mode 100644 index 0000000000..f665431fab --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2910Test.java @@ -0,0 +1,129 @@ +/** + * 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.bugs; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleClientsTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import java.util.Vector; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertTrue; + +@RunWith(BlockJUnit4ClassRunner.class) +public class AMQ2910Test extends JmsMultipleClientsTestSupport { + + final int maxConcurrency = 60; + final int msgCount = 200; + final Vector exceptions = new Vector(); + + @Override + protected BrokerService createBroker() throws Exception { + //persistent = true; + BrokerService broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector("tcp://localhost:0"); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setPendingQueuePolicy(new FilePendingQueueMessageStoragePolicy()); + defaultEntry.setCursorMemoryHighWaterMark(50); + defaultEntry.setMemoryLimit(500*1024); + defaultEntry.setProducerFlowControl(false); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + + broker.getSystemUsage().getMemoryUsage().setLimit(1000 * 1024); + + return broker; + } + + @Test(timeout = 30 * 1000) + public void testConcurrentSendToPendingCursor() throws Exception { + final ActiveMQConnectionFactory factory = + new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri()); + factory.setCloseTimeout(30000); + ExecutorService executor = Executors.newCachedThreadPool(); + for (int i=0; i consumerThreads = new ArrayList(); + for (int i = 0; i < MAX_CONSUMER; i++) { + ConsumerThread thread = new ConsumerThread(); + thread.start(); + consumerThreads.add(thread); + } + sendMessages(); + + boolean allMessagesReceived = messageCountDown.await(60, TimeUnit.SECONDS); + assertTrue(allMessagesReceived); + + for (Thread thread : consumerThreads) { + thread.join(TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS)); + assertFalse(thread.isAlive()); + } + kahaDB.forceCleanup(); + assertEquals("Expect only one active KahaDB log file after cleanup", 1, kahaDB.getFileMapSize()); + } + + private void sendMessages() throws Exception { + ConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME)); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + for (int i = 0; i < MAX_MESSAGES; i++) { + BytesMessage message = session.createBytesMessage(); + message.writeBytes(new byte[200]); + producer.send(message); + } + producer.close(); + session.close(); + connection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3014Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3014Test.java new file mode 100644 index 0000000000..dcd5064c6c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3014Test.java @@ -0,0 +1,208 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.Connection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.thread.Task; +import org.apache.activemq.thread.TaskRunner; +import org.apache.activemq.thread.TaskRunnerFactory; +import org.apache.activemq.transport.*; +import org.apache.activemq.transport.discovery.simple.SimpleDiscoveryAgent; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * This test involves the creation of a local and remote broker, both of which + * communicate over VM and TCP. The local broker establishes a bridge to the + * remote broker for the purposes of verifying that broker info is only + * transfered once the local broker's ID is known to the bridge support. + */ +public class AMQ3014Test { + // Change this URL to be an unused port. + private static final String BROKER_URL = "tcp://localhost:0"; + + private List remoteBrokerInfos = Collections + .synchronizedList(new ArrayList()); + + private BrokerService localBroker = new BrokerService(); + + // Override the "remote" broker so that it records all (remote) BrokerInfos + // that it receives. + private BrokerService remoteBroker = new BrokerService() { + @Override + protected TransportConnector createTransportConnector(URI brokerURI) + throws Exception { + TransportServer transport = TransportFactorySupport.bind(this, brokerURI); + return new TransportConnector(transport) { + @Override + protected Connection createConnection(Transport transport) + throws IOException { + Connection connection = super.createConnection(transport); + final TransportListener proxiedListener = transport + .getTransportListener(); + transport.setTransportListener(new TransportListener() { + + @Override + public void onCommand(Object command) { + if (command instanceof BrokerInfo) { + remoteBrokerInfos.add((BrokerInfo) command); + } + proxiedListener.onCommand(command); + } + + @Override + public void onException(IOException error) { + proxiedListener.onException(error); + } + + @Override + public void transportInterupted() { + proxiedListener.transportInterupted(); + } + + @Override + public void transportResumed() { + proxiedListener.transportResumed(); + } + }); + return connection; + } + + }; + } + }; + + @Before + public void init() throws Exception { + localBroker.setBrokerName("localBroker"); + localBroker.setPersistent(false); + localBroker.setUseJmx(false); + localBroker.setSchedulerSupport(false); + + remoteBroker.setBrokerName("remoteBroker"); + remoteBroker.setPersistent(false); + remoteBroker.setUseJmx(false); + remoteBroker.addConnector(BROKER_URL); + remoteBroker.setSchedulerSupport(false); + } + + @After + public void cleanup() throws Exception { + try { + localBroker.stop(); + } finally { + remoteBroker.stop(); + } + } + + /** + * This test verifies that the local broker's ID is typically known by the + * bridge support before the local broker's BrokerInfo is sent to the remote + * broker. + */ + @Test + public void NormalCaseTest() throws Exception { + runTest(0, 3000); + } + + /** + * This test verifies that timing can arise under which the local broker's + * ID is not known by the bridge support before the local broker's + * BrokerInfo is sent to the remote broker. + */ + @Test + public void DelayedCaseTest() throws Exception { + runTest(500, 3000); + } + + private void runTest(final long taskRunnerDelay, long timeout) + throws Exception { + // Add a network connector to the local broker that will create a bridge + // to the remote broker. + DiscoveryNetworkConnector dnc = new DiscoveryNetworkConnector(); + SimpleDiscoveryAgent da = new SimpleDiscoveryAgent(); + da.setServices(remoteBroker.getTransportConnectors().get(0).getPublishableConnectString()); + dnc.setDiscoveryAgent(da); + localBroker.addNetworkConnector(dnc); + + // Before starting the local broker, intercept the task runner factory + // so that the + // local VMTransport dispatcher is artificially delayed. + final TaskRunnerFactory realTaskRunnerFactory = localBroker + .getTaskRunnerFactory(); + localBroker.setTaskRunnerFactory(new TaskRunnerFactory() { + public TaskRunner createTaskRunner(Task task, String name) { + final TaskRunner realTaskRunner = realTaskRunnerFactory + .createTaskRunner(task, name); + if (name.startsWith("ActiveMQ Connection Dispatcher: ")) { + return new TaskRunner() { + @Override + public void shutdown() throws InterruptedException { + realTaskRunner.shutdown(); + } + + @Override + public void shutdown(long timeout) + throws InterruptedException { + realTaskRunner.shutdown(timeout); + } + + @Override + public void wakeup() throws InterruptedException { + Thread.sleep(taskRunnerDelay); + realTaskRunner.wakeup(); + } + }; + } else { + return realTaskRunnerFactory.createTaskRunner(task, name); + } + } + }); + + // Start the brokers and wait for the bridge to be created; the remote + // broker is started first to ensure it is available for the local + // broker to connect to. + remoteBroker.start(); + localBroker.start(); + + // Wait for the remote broker to receive the local broker's BrokerInfo + // and then verify the local broker's ID is known. + long startTimeMillis = System.currentTimeMillis(); + while (remoteBrokerInfos.isEmpty() + && (System.currentTimeMillis() - startTimeMillis) < timeout) { + Thread.sleep(100); + } + + Assert.assertFalse("Timed out waiting for bridge to form.", + remoteBrokerInfos.isEmpty()); + ; + Assert.assertNotNull("Local broker ID is null.", remoteBrokerInfos.get( + 0).getBrokerId()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3120Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3120Test.java new file mode 100644 index 0000000000..bfff0fd95f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3120Test.java @@ -0,0 +1,148 @@ +/** + * 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.bugs; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.ConsumerThread; +import org.apache.activemq.util.ProducerThread; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.junit.Test; + +import javax.jms.*; + +import java.io.File; + +import static org.junit.Assert.assertEquals; + +public class AMQ3120Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ3120Test.class); + + BrokerService broker = null; + File kahaDbDir = null; + private final Destination destination = new ActiveMQQueue("AMQ3120Test"); + final String payload = new String(new byte[1024]); + + protected void startBroker(boolean delete) throws Exception { + broker = new BrokerService(); + + //Start with a clean directory + kahaDbDir = new File(broker.getBrokerDataDirectory(), "KahaDB"); + deleteDir(kahaDbDir); + + broker.setSchedulerSupport(false); + broker.setDeleteAllMessagesOnStartup(delete); + broker.setPersistent(true); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:0"); + + PolicyMap map = new PolicyMap(); + PolicyEntry entry = new PolicyEntry(); + entry.setUseCache(false); + map.setDefaultEntry(entry); + broker.setDestinationPolicy(map); + + configurePersistence(broker, delete); + + broker.start(); + LOG.info("Starting broker.."); + } + + protected void configurePersistence(BrokerService brokerService, boolean deleteAllOnStart) throws Exception { + KahaDBPersistenceAdapter adapter = (KahaDBPersistenceAdapter) brokerService.getPersistenceAdapter(); + + // ensure there are a bunch of data files but multiple entries in each + adapter.setJournalMaxFileLength(1024 * 20); + + // speed up the test case, checkpoint an cleanup early and often + adapter.setCheckpointInterval(500); + adapter.setCleanupInterval(500); + + if (!deleteAllOnStart) { + adapter.setForceRecoverIndex(true); + } + + } + + private boolean deleteDir(File dir) { + if (dir.isDirectory()) { + String[] children = dir.list(); + for (int i = 0; i < children.length; i++) { + boolean success = deleteDir(new File(dir, children[i])); + if (!success) { + return false; + } + } + } + + return dir.delete(); + } + + private int getFileCount(File dir){ + if (dir.isDirectory()) { + String[] children = dir.list(); + return children.length; + } + + return 0; + } + + @Test + public void testCleanupOfFiles() throws Exception { + final int messageCount = 500; + startBroker(true); + int fileCount = getFileCount(kahaDbDir); + assertEquals(4, fileCount); + + Connection connection = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getConnectUri()).createConnection(); + connection.start(); + Session producerSess = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session consumerSess = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ProducerThread producer = new ProducerThread(producerSess, destination) { + @Override + protected Message createMessage(int i) throws Exception { + return sess.createTextMessage(payload + "::" + i); + } + }; + producer.setSleep(650); + producer.setMessageCount(messageCount); + ConsumerThread consumer = new ConsumerThread(consumerSess, destination); + consumer.setBreakOnNull(false); + consumer.setMessageCount(messageCount); + + producer.start(); + consumer.start(); + + producer.join(); + consumer.join(); + + assertEquals("consumer got all produced messages", producer.getMessageCount(), consumer.getReceived()); + + broker.stop(); + broker.waitUntilStopped(); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3140Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3140Test.java new file mode 100644 index 0000000000..fd71558cf9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3140Test.java @@ -0,0 +1,145 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ3140Test { + + private static final int MESSAGES_PER_THREAD = 100; + + private static final int THREAD_COUNT = 10; + + private BrokerService broker; + + private static final String QUEUE_NAME = "test"; + + private static class Sender extends Thread { + + private static final int DELAY = 3000; + + @Override + public void run() { + try { + ConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME)); + Message message = session.createTextMessage("test"); + for (int i = 0; i < MESSAGES_PER_THREAD; i++) { + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, DELAY); + producer.send(message); + } + session.close(); + connection.close(); + } catch (JMSException e) { + fail(e.getMessage()); + } + } + } + + @Before + public void setup() throws Exception { + File schedulerDirectory = new File("target/test/ScheduledDB"); + + IOHelper.mkdirs(schedulerDirectory); + IOHelper.deleteChildren(schedulerDirectory); + + broker = new BrokerService(); + broker.setSchedulerSupport(true); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(true); + broker.setDataDirectory("target"); + broker.setSchedulerDirectoryFile(schedulerDirectory); + broker.setUseJmx(false); + broker.addConnector("vm://localhost"); + + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } + + @Test + public void noMessageLostOnConcurrentScheduling() throws JMSException, InterruptedException { + + final AtomicLong receiveCounter = new AtomicLong(); + + ConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + receiveCounter.incrementAndGet(); + } + }); + + List senderThreads = new ArrayList(); + for (int i = 0; i < THREAD_COUNT; i++) { + Sender sender = new Sender(); + senderThreads.add(sender); + } + for (Sender sender : senderThreads) { + sender.start(); + } + for (Sender sender : senderThreads) { + sender.join(); + } + + // wait until all scheduled messages has been received + TimeUnit.MINUTES.sleep(2); + + session.close(); + connection.close(); + + assertEquals(MESSAGES_PER_THREAD * THREAD_COUNT, receiveCounter.get()); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3141Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3141Test.java new file mode 100644 index 0000000000..1209bd7a59 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3141Test.java @@ -0,0 +1,117 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ3141Test { + + private static final int MAX_MESSAGES = 100; + + private static final long DELAY_IN_MS = 100; + + private static final String QUEUE_NAME = "target.queue"; + + private BrokerService broker; + + private final CountDownLatch messageCountDown = new CountDownLatch(MAX_MESSAGES); + + private ConnectionFactory factory; + + @Before + public void setup() throws Exception { + + broker = new BrokerService(); + broker.setPersistent(true); + broker.setSchedulerSupport(true); + broker.setDataDirectory("target"); + broker.setUseJmx(false); + broker.addConnector("vm://localhost"); + + File schedulerDirectory = new File("target/test/ScheduledDB"); + IOHelper.mkdirs(schedulerDirectory); + IOHelper.deleteChildren(schedulerDirectory); + broker.setSchedulerDirectoryFile(schedulerDirectory); + + broker.start(); + broker.waitUntilStarted(); + + factory = new ActiveMQConnectionFactory("vm://localhost"); + } + + private void sendMessages() throws Exception { + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME)); + for (int i = 0; i < MAX_MESSAGES; i++) { + Message message = session.createTextMessage(); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, DELAY_IN_MS); + producer.send(message); + } + connection.close(); + } + + @Test + public void testNoMissingMessagesOnShortScheduleDelay() throws Exception { + + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + messageCountDown.countDown(); + } + }); + sendMessages(); + + boolean receiveComplete = messageCountDown.await(5, TimeUnit.SECONDS); + + connection.close(); + + assertTrue("expect all messages received but " + messageCountDown.getCount() + " are missing", receiveComplete); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3145Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3145Test.java new file mode 100644 index 0000000000..81128bdac0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3145Test.java @@ -0,0 +1,133 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3145Test { + private static final Logger LOG = LoggerFactory.getLogger(AMQ3145Test.class); + private final String MESSAGE_TEXT = new String(new byte[1024]); + BrokerService broker; + ConnectionFactory factory; + Connection connection; + Session session; + Queue queue; + MessageConsumer consumer; + + @Before + public void createBroker() throws Exception { + createBroker(true); + } + + public void createBroker(boolean deleteAll) throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(deleteAll); + broker.setDataDirectory("target/AMQ3145Test"); + broker.setUseJmx(true); + broker.getManagementContext().setCreateConnector(false); + broker.addConnector("tcp://localhost:0"); + broker.start(); + broker.waitUntilStarted(); + factory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri().toString()); + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + } + + @After + public void tearDown() throws Exception { + if (consumer != null) { + consumer.close(); + } + session.close(); + connection.stop(); + connection.close(); + broker.stop(); + } + + @Test + public void testCacheDisableReEnable() throws Exception { + createProducerAndSendMessages(1); + QueueViewMBean proxy = getProxyToQueueViewMBean(); + assertTrue("cache is enabled", proxy.isCacheEnabled()); + tearDown(); + createBroker(false); + proxy = getProxyToQueueViewMBean(); + assertEquals("one pending message", 1, proxy.getQueueSize()); + assertTrue("cache is disabled when there is a pending message", !proxy.isCacheEnabled()); + + createConsumer(1); + createProducerAndSendMessages(1); + assertTrue("cache is enabled again on next send when there are no messages", proxy.isCacheEnabled()); + } + + private QueueViewMBean getProxyToQueueViewMBean() + throws MalformedObjectNameException, JMSException { + ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq" + + ":destinationType=Queue,destinationName=" + queue.getQueueName() + + ",type=Broker,brokerName=localhost"); + QueueViewMBean proxy = (QueueViewMBean) broker.getManagementContext() + .newProxyInstance(queueViewMBeanName, + QueueViewMBean.class, true); + return proxy; + } + + private void createProducerAndSendMessages(int numToSend) throws Exception { + queue = session.createQueue("test1"); + MessageProducer producer = session.createProducer(queue); + for (int i = 0; i < numToSend; i++) { + TextMessage message = session.createTextMessage(MESSAGE_TEXT + i); + if (i != 0 && i % 50000 == 0) { + LOG.info("sent: " + i); + } + producer.send(message); + } + producer.close(); + } + + private void createConsumer(int numToConsume) throws Exception { + consumer = session.createConsumer(queue); + // wait for buffer fill out + for (int i = 0; i < numToConsume; ++i) { + Message message = consumer.receive(2000); + message.acknowledge(); + } + consumer.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3157Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3157Test.java new file mode 100644 index 0000000000..f18af6ffc1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3157Test.java @@ -0,0 +1,175 @@ +/** + * 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.bugs; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.virtual.MirroredQueue; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.spring.ConsumerBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3157Test extends EmbeddedBrokerTestSupport { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3157Test.class); + private Connection connection; + + public void testInactiveMirroredQueueIsCleanedUp() throws Exception { + + if (connection == null) { + connection = createConnection(); + } + connection.start(); + + ConsumerBean messageList = new ConsumerBean(); + messageList.setVerbose(true); + + ActiveMQDestination consumeDestination = createConsumeDestination(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + LOG.info("Consuming from: " + consumeDestination); + + MessageConsumer c1 = session.createConsumer(consumeDestination); + c1.setMessageListener(messageList); + + // create topic producer + ActiveMQQueue sendDestination = new ActiveMQQueue(getQueueName()); + LOG.info("Sending to: " + sendDestination); + + MessageProducer producer = session.createProducer(sendDestination); + assertNotNull(producer); + + final int total = 10; + for (int i = 0; i < total; i++) { + producer.send(session.createTextMessage("message: " + i)); + } + + messageList.assertMessagesArrived(total); + LOG.info("Received: " + messageList); + messageList.flushMessages(); + + MessageConsumer c2 = session.createConsumer(sendDestination); + c2.setMessageListener(messageList); + messageList.assertMessagesArrived(total); + LOG.info("Q Received: " + messageList); + + 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))); + + Thread.sleep(TimeUnit.SECONDS.toMillis(10)); + + 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))); + } + } + + protected ActiveMQDestination createConsumeDestination() { + return new ActiveMQTopic("VirtualTopic.Mirror." + getQueueName()); + } + + protected String getQueueName() { + return "My.Queue"; + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseMirroredQueues(true); + answer.setPersistent(isPersistent()); + answer.setSchedulePeriodForDestinationPurge(1000); + + PolicyEntry entry = new PolicyEntry(); + entry.setGcInactiveDestinations(true); + entry.setInactiveTimoutBeforeGC(5000); + entry.setProducerFlowControl(true); + PolicyMap map = new PolicyMap(); + map.setDefaultEntry(entry); + + MirroredQueue mirrorQ = new MirroredQueue(); + mirrorQ.setCopyMessage(true); + DestinationInterceptor[] destinationInterceptors = new DestinationInterceptor[]{mirrorQ}; + answer.setDestinationInterceptors(destinationInterceptors); + + answer.setDestinationPolicy(map); + answer.addConnector(bindAddress); + + return answer; + } + + protected DestinationViewMBean createView(ActiveMQDestination destination) throws Exception { + String domain = "org.apache.activemq"; + ObjectName name; + if (destination.isQueue()) { + name = new ObjectName(domain + ":BrokerName=localhost,Type=Queue,Destination=" + destination.getPhysicalName()); + } else { + name = new ObjectName(domain + ":BrokerName=localhost,Type=Topic,Destination=" + destination.getPhysicalName()); + } + return (DestinationViewMBean) broker.getManagementContext().newProxyInstance(name, DestinationViewMBean.class, + true); + } + + protected ObjectName createObjectName(ActiveMQDestination destination) throws Exception { + String domain = "org.apache.activemq"; + ObjectName name; + if (destination.isQueue()) { + name = new ObjectName(domain + ":type=Broker,brokerName=localhost," + + "destinationType=Queue,destinationName=" + destination.getPhysicalName()); + } else { + name = new ObjectName(domain + ":type=Broker,brokerName=localhost," + + "destinationType=Topic,destinationName=" + destination.getPhysicalName()); + } + + return name; + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3167Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3167Test.java new file mode 100644 index 0000000000..7e3048abe9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3167Test.java @@ -0,0 +1,462 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test the loss of messages detected during testing with ActiveMQ 5.4.1 and 5.4.2. + *

+ * Symptoms: - 1 record is lost "early" in the stream. - no more records lost. + *

+ * Test Configuration: - Broker Settings: - Destination Policy - Occurs with "Destination Policy" using Store Cursor and + * a memory limit - Not reproduced without "Destination Policy" defined - Persistence Adapter - Memory: Does not occur. + * - KahaDB: Occurs. - Messages - Occurs with TextMessage and BinaryMessage - Persistent messages. + *

+ * Notes: - Lower memory limits increase the rate of occurrence. - Higher memory limits may prevent the problem + * (probably because memory limits not reached). - Producers sending a number of messages before consumers come online + * increases rate of occurrence. + */ + +public class AMQ3167Test { + protected BrokerService embeddedBroker; + + protected static final int MEMORY_LIMIT = 16 * 1024; + + protected static boolean Debug_f = false; + + protected long Producer_stop_time = 0; + protected long Consumer_stop_time = 0; + protected long Consumer_startup_delay_ms = 2000; + protected boolean Stop_after_error = true; + + protected Connection JMS_conn; + protected long Num_error = 0; + + // // //// + // // UTILITIES //// + // // //// + + /** + * Create a new, unsecured, client connection to the test broker using the given username and password. This + * connection bypasses all security. + *

+ * Don't forget to start the connection or no messages will be received by consumers even though producers will work + * fine. + * + * @username name of the JMS user for the connection; may be null. + * @password Password for the JMS user; may be null. + */ + + protected Connection createUnsecuredConnection(String username, String password) throws javax.jms.JMSException { + ActiveMQConnectionFactory conn_fact; + + conn_fact = new ActiveMQConnectionFactory(embeddedBroker.getVmConnectorURI()); + + return conn_fact.createConnection(username, password); + } + + // // //// + // // TEST FUNCTIONALITY //// + // // //// + + @Before + public void testPrep() throws Exception { + embeddedBroker = new BrokerService(); + configureBroker(embeddedBroker); + embeddedBroker.start(); + embeddedBroker.waitUntilStarted(); + + // Prepare the connection + JMS_conn = createUnsecuredConnection(null, null); + JMS_conn.start(); + } + + @After + public void testCleanup() throws java.lang.Exception { + JMS_conn.stop(); + embeddedBroker.stop(); + } + + protected void configureBroker(BrokerService broker_svc) throws Exception { + + broker_svc.setBrokerName("testbroker1"); + + broker_svc.setUseJmx(false); + broker_svc.setPersistent(true); + broker_svc.setDataDirectory("target/AMQ3167Test"); + configureDestinationPolicy(broker_svc); + } + + /** + * NOTE: overrides any prior policy map defined for the broker service. + */ + + protected void configureDestinationPolicy(BrokerService broker_svc) { + PolicyMap pol_map; + PolicyEntry pol_ent; + ArrayList ent_list; + + ent_list = new ArrayList(); + + // + // QUEUES + // + + pol_ent = new PolicyEntry(); + pol_ent.setQueue(">"); + pol_ent.setMemoryLimit(MEMORY_LIMIT); + pol_ent.setProducerFlowControl(false); + ent_list.add(pol_ent); + + // + // COMPLETE POLICY MAP + // + + pol_map = new PolicyMap(); + pol_map.setPolicyEntries(ent_list); + + broker_svc.setDestinationPolicy(pol_map); + } + + // // //// + // // TEST //// + // // //// + + @Test + public void testQueueLostMessage() throws Exception { + Destination dest; + + dest = ActiveMQDestination.createDestination("lostmsgtest.queue", ActiveMQDestination.QUEUE_TYPE); + + // 10 seconds from now + Producer_stop_time = java.lang.System.nanoTime() + (10L * 1000000000L); + + // 15 seconds from now + Consumer_stop_time = Producer_stop_time + (5L * 1000000000L); + + runLostMsgTest(dest, 1000000, 1, 1, false); + + // Make sure failures in the threads are thoroughly reported in the JUnit framework. + assertTrue(Num_error == 0); + } + + /** + * + */ + + protected static void log(String msg) { + if (Debug_f) + java.lang.System.err.println(msg); + } + + /** + * Main body of the lost-message test. + */ + + protected void runLostMsgTest(Destination dest, int num_msg, int num_send_per_sess, int num_recv_per_sess, boolean topic_f) throws Exception { + Thread prod_thread; + Thread cons_thread; + String tag; + Session sess; + MessageProducer prod; + MessageConsumer cons; + int ack_mode; + + // + // Start the producer + // + + tag = "prod"; + log(">> Starting producer " + tag); + + sess = JMS_conn.createSession((num_send_per_sess > 1), Session.AUTO_ACKNOWLEDGE); + prod = sess.createProducer(dest); + + prod_thread = new producerThread(sess, prod, tag, num_msg, num_send_per_sess); + prod_thread.start(); + log("Started producer " + tag); + + // + // Delay before starting consumers + // + + log("Waiting before starting consumers"); + java.lang.Thread.sleep(Consumer_startup_delay_ms); + + // + // Now create and start the consumer + // + + tag = "cons"; + log(">> Starting consumer"); + + if (num_recv_per_sess > 1) + ack_mode = Session.CLIENT_ACKNOWLEDGE; + else + ack_mode = Session.AUTO_ACKNOWLEDGE; + + sess = JMS_conn.createSession(false, ack_mode); + cons = sess.createConsumer(dest); + + cons_thread = new consumerThread(sess, cons, tag, num_msg, num_recv_per_sess); + cons_thread.start(); + log("Started consumer " + tag); + + // + // Wait for the producer and consumer to finish. + // + + log("< waiting for producer."); + prod_thread.join(); + + log("< waiting for consumer."); + cons_thread.join(); + + log("Shutting down"); + } + + // // //// + // // INTERNAL CLASSES //// + // // //// + + /** + * Producer thread - runs a single producer until the maximum number of messages is sent, the producer stop time is + * reached, or a test error is detected. + */ + + protected class producerThread extends Thread { + protected Session msgSess; + protected MessageProducer msgProd; + protected String producerTag; + protected int numMsg; + protected int numPerSess; + protected long producer_stop_time; + + producerThread(Session sess, MessageProducer prod, String tag, int num_msg, int sess_size) { + super(); + + producer_stop_time = 0; + msgSess = sess; + msgProd = prod; + producerTag = tag; + numMsg = num_msg; + numPerSess = sess_size; + } + + public void execTest() throws Exception { + Message msg; + int sess_start; + int cur; + + sess_start = 0; + cur = 0; + while ((cur < numMsg) && (!didTimeOut()) && ((!Stop_after_error) || (Num_error == 0))) { + msg = msgSess.createTextMessage("test message from " + producerTag); + msg.setStringProperty("testprodtag", producerTag); + msg.setIntProperty("seq", cur); + + if (msg instanceof ActiveMQMessage) { + ((ActiveMQMessage) msg).setResponseRequired(true); + } + + // + // Send the message. + // + + msgProd.send(msg); + cur++; + + // + // Commit if the number of messages per session has been reached, and + // transactions are being used (only when > 1 msg per sess). + // + + if ((numPerSess > 1) && ((cur - sess_start) >= numPerSess)) { + msgSess.commit(); + sess_start = cur; + } + } + + // Make sure to send the final commit, if there were sends since the last commit. + if ((numPerSess > 1) && ((cur - sess_start) > 0)) + msgSess.commit(); + + if (cur < numMsg) + log("* Producer " + producerTag + " timed out at " + java.lang.System.nanoTime() + " (stop time " + producer_stop_time + ")"); + } + + /** + * Check whether it is time for the producer to terminate. + */ + + protected boolean didTimeOut() { + if ((Producer_stop_time > 0) && (java.lang.System.nanoTime() >= Producer_stop_time)) + return true; + + return false; + } + + /** + * Run the producer. + */ + + @Override + public void run() { + try { + log("- running producer " + producerTag); + execTest(); + log("- finished running producer " + producerTag); + } catch (Throwable thrown) { + Num_error++; + fail("producer " + producerTag + " failed: " + thrown.getMessage()); + throw new Error("producer " + producerTag + " failed", thrown); + } + } + + @Override + public String toString() { + return producerTag; + } + } + + /** + * Producer thread - runs a single consumer until the maximum number of messages is received, the consumer stop time + * is reached, or a test error is detected. + */ + + protected class consumerThread extends Thread { + protected Session msgSess; + protected MessageConsumer msgCons; + protected String consumerTag; + protected int numMsg; + protected int numPerSess; + + consumerThread(Session sess, MessageConsumer cons, String tag, int num_msg, int sess_size) { + super(); + + msgSess = sess; + msgCons = cons; + consumerTag = tag; + numMsg = num_msg; + numPerSess = sess_size; + } + + public void execTest() throws Exception { + Message msg; + int sess_start; + int cur; + + msg = null; + sess_start = 0; + cur = 0; + + while ((cur < numMsg) && (!didTimeOut()) && ((!Stop_after_error) || (Num_error == 0))) { + // + // Use a timeout of 1 second to periodically check the consumer timeout. + // + msg = msgCons.receive(1000); + if (msg != null) { + checkMessage(msg, cur); + cur++; + + if ((numPerSess > 1) && ((cur - sess_start) >= numPerSess)) { + msg.acknowledge(); + sess_start = cur; + } + } + } + + // Acknowledge the last messages, if they were not yet acknowledged. + if ((numPerSess > 1) && ((cur - sess_start) > 0)) + msg.acknowledge(); + + if (cur < numMsg) + log("* Consumer " + consumerTag + " timed out"); + } + + /** + * Check whether it is time for the consumer to terminate. + */ + + protected boolean didTimeOut() { + if ((Consumer_stop_time > 0) && (java.lang.System.nanoTime() >= Consumer_stop_time)) + return true; + + return false; + } + + /** + * Verify the message received. Sequence numbers are checked and are expected to exactly match the message + * number (starting at 0). + */ + + protected void checkMessage(Message msg, int exp_seq) throws javax.jms.JMSException { + int seq; + + seq = msg.getIntProperty("seq"); + + if (exp_seq != seq) { + Num_error++; + fail("*** Consumer " + consumerTag + " expected seq " + exp_seq + "; received " + seq); + } + } + + /** + * Run the consumer. + */ + + @Override + public void run() { + try { + log("- running consumer " + consumerTag); + execTest(); + log("- running consumer " + consumerTag); + } catch (Throwable thrown) { + Num_error++; + fail("consumer " + consumerTag + " failed: " + thrown.getMessage()); + throw new Error("consumer " + consumerTag + " failed", thrown); + } + } + + @Override + public String toString() { + return consumerTag; + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3274Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3274Test.java new file mode 100644 index 0000000000..48c5cbb937 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3274Test.java @@ -0,0 +1,734 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3274Test { + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3274Test.class); + + protected static int Next_broker_num = 0; + protected EmbeddedTcpBroker broker1; + protected EmbeddedTcpBroker broker2; + + protected int nextEchoId = 0; + protected boolean testError = false; + + protected int echoResponseFill = 0; // Number of "filler" response messages per request + + public AMQ3274Test() throws Exception { + broker1 = new EmbeddedTcpBroker(); + broker2 = new EmbeddedTcpBroker(); + + broker1.coreConnectTo(broker2, true); + broker2.coreConnectTo(broker1, true); + } + + public void logMessage(String msg) { + System.out.println(msg); + System.out.flush(); + } + + public void testMessages(Session sess, MessageProducer req_prod, Destination resp_dest, int num_msg) throws Exception { + MessageConsumer resp_cons; + TextMessage msg; + MessageClient cons_client; + int cur; + int tot_expected; + + resp_cons = sess.createConsumer(resp_dest); + + cons_client = new MessageClient(resp_cons, num_msg); + cons_client.start(); + + cur = 0; + while ((cur < num_msg) && (!testError)) { + msg = sess.createTextMessage("MSG AAAA " + cur); + msg.setIntProperty("SEQ", 100 + cur); + msg.setStringProperty("TEST", "TOPO"); + msg.setJMSReplyTo(resp_dest); + + if (cur == (num_msg - 1)) + msg.setBooleanProperty("end-of-response", true); + + req_prod.send(msg); + + cur++; + } + + cons_client.waitShutdown(5000); + + if (cons_client.shutdown()) { + LOG.debug("Consumer client shutdown complete"); + } else { + LOG.debug("Consumer client shutdown incomplete!!!"); + } + + tot_expected = num_msg * (echoResponseFill + 1); + + if (cons_client.getNumMsgReceived() == tot_expected) { + LOG.info("Have " + tot_expected + " messages, as-expected"); + } else { + LOG.error("Have " + cons_client.getNumMsgReceived() + " messages; expected " + tot_expected); + testError = true; + } + + resp_cons.close(); + } + + /** + * Test one destination between the given "producer broker" and + * "consumer broker" specified. + */ + public void testOneDest(Connection conn, Session sess, Destination cons_dest, String prod_broker_url, String cons_broker_url, int num_msg) throws Exception { + int echo_id; + + EchoService echo_svc; + String echo_queue_name; + Destination prod_dest; + MessageProducer msg_prod; + + synchronized (this) { + echo_id = this.nextEchoId; + this.nextEchoId++; + } + + echo_queue_name = "echo.queue." + echo_id; + + LOG.trace("destroying the echo queue in case an old one exists"); + removeQueue(conn, echo_queue_name); + + echo_svc = new EchoService(echo_queue_name, prod_broker_url); + echo_svc.start(); + + LOG.trace("Creating echo queue and producer"); + prod_dest = sess.createQueue(echo_queue_name); + msg_prod = sess.createProducer(prod_dest); + + testMessages(sess, msg_prod, cons_dest, num_msg); + + echo_svc.shutdown(); + msg_prod.close(); + } + + /** + * TEST TEMPORARY TOPICS + */ + public void testTempTopic(String prod_broker_url, String cons_broker_url) throws Exception { + Connection conn; + Session sess; + Destination cons_dest; + int num_msg; + + num_msg = 5; + + LOG.info("TESTING TEMP TOPICS " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + LOG.trace("Creating destination"); + cons_dest = sess.createTemporaryTopic(); + + testOneDest(conn, sess, cons_dest, prod_broker_url, cons_broker_url, num_msg); + + sess.close(); + conn.close(); + } + + /** + * TEST TOPICS + */ + public void testTopic(String prod_broker_url, String cons_broker_url) throws Exception { + int num_msg; + + Connection conn; + Session sess; + String topic_name; + + Destination cons_dest; + + num_msg = 5; + + LOG.info("TESTING TOPICS " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + topic_name = "topotest2.perm.topic"; + LOG.trace("Removing existing Topic"); + removeTopic(conn, topic_name); + LOG.trace("Creating Topic, " + topic_name); + cons_dest = sess.createTopic(topic_name); + + testOneDest(conn, sess, cons_dest, prod_broker_url, cons_broker_url, num_msg); + + removeTopic(conn, topic_name); + sess.close(); + conn.close(); + } + + /** + * TEST TEMPORARY QUEUES + */ + public void testTempQueue(String prod_broker_url, String cons_broker_url) throws Exception { + int num_msg; + + Connection conn; + Session sess; + + Destination cons_dest; + + num_msg = 5; + + LOG.info("TESTING TEMP QUEUES " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + LOG.trace("Creating destination"); + cons_dest = sess.createTemporaryQueue(); + + testOneDest(conn, sess, cons_dest, prod_broker_url, cons_broker_url, num_msg); + + sess.close(); + conn.close(); + } + + /** + * TEST QUEUES + */ + public void testQueue(String prod_broker_url, String cons_broker_url) throws Exception { + int num_msg; + + Connection conn; + Session sess; + String queue_name; + + Destination cons_dest; + + num_msg = 5; + + LOG.info("TESTING QUEUES " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + queue_name = "topotest2.perm.queue"; + LOG.trace("Removing existing Queue"); + removeQueue(conn, queue_name); + LOG.trace("Creating Queue, " + queue_name); + cons_dest = sess.createQueue(queue_name); + + testOneDest(conn, sess, cons_dest, prod_broker_url, cons_broker_url, num_msg); + + removeQueue(conn, queue_name); + sess.close(); + conn.close(); + } + + @Test + public void run() throws Exception { + Thread start1; + Thread start2; + + testError = false; + + // Use threads to avoid startup deadlock since the first broker started waits until + // it knows the name of the remote broker before finishing its startup, which means + // the remote must already be running. + + start1 = new Thread() { + public void run() { + try { + broker1.start(); + } catch (Exception ex) { + LOG.error(null, ex); + } + } + }; + + start2 = new Thread() { + public void run() { + try { + broker2.start(); + } catch (Exception ex) { + LOG.error(null, ex); + } + } + }; + + start1.start(); + start2.start(); + + start1.join(); + start2.join(); + + if (!testError) { + this.testTempTopic(broker1.getConnectionUrl(), broker2.getConnectionUrl()); + } + if (!testError) { + this.testTempQueue(broker1.getConnectionUrl(), broker2.getConnectionUrl()); + } + if (!testError) { + this.testTopic(broker1.getConnectionUrl(), broker2.getConnectionUrl()); + } + if (!testError) { + this.testQueue(broker1.getConnectionUrl(), broker2.getConnectionUrl()); + } + Thread.sleep(100); + + shutdown(); + + assertTrue(!testError); + } + + public void shutdown() throws Exception { + broker1.stop(); + broker2.stop(); + } + + /** + * @param args + * the command line arguments + */ + public static void main(String[] args) { + AMQ3274Test main_obj; + + try { + main_obj = new AMQ3274Test(); + main_obj.run(); + } catch (Exception ex) { + ex.printStackTrace(); + LOG.error(null, ex); + System.exit(0); + } + } + + protected Connection createConnection(String url) throws Exception { + return org.apache.activemq.ActiveMQConnection.makeConnection(url); + } + + protected static void removeQueue(Connection conn, String dest_name) throws java.lang.Exception { + org.apache.activemq.command.ActiveMQDestination dest; + + if (conn instanceof org.apache.activemq.ActiveMQConnection) { + dest = org.apache.activemq.command.ActiveMQDestination.createDestination(dest_name, + (byte) org.apache.activemq.command.ActiveMQDestination.QUEUE_TYPE); + ((org.apache.activemq.ActiveMQConnection) conn).destroyDestination(dest); + } + } + + protected static void removeTopic(Connection conn, String dest_name) throws java.lang.Exception { + org.apache.activemq.command.ActiveMQDestination dest; + + if (conn instanceof org.apache.activemq.ActiveMQConnection) { + dest = org.apache.activemq.command.ActiveMQDestination.createDestination(dest_name, + (byte) org.apache.activemq.command.ActiveMQDestination.TOPIC_TYPE); + ((org.apache.activemq.ActiveMQConnection) conn).destroyDestination(dest); + } + } + + @SuppressWarnings("rawtypes") + public static String fmtMsgInfo(Message msg) throws Exception { + StringBuilder msg_desc; + String prop; + Enumeration prop_enum; + + msg_desc = new StringBuilder(); + msg_desc = new StringBuilder(); + + if (msg instanceof TextMessage) { + msg_desc.append(((TextMessage) msg).getText()); + } else { + msg_desc.append("["); + msg_desc.append(msg.getClass().getName()); + msg_desc.append("]"); + } + + prop_enum = msg.getPropertyNames(); + while (prop_enum.hasMoreElements()) { + prop = (String) prop_enum.nextElement(); + msg_desc.append("; "); + msg_desc.append(prop); + msg_desc.append("="); + msg_desc.append(msg.getStringProperty(prop)); + } + + return msg_desc.toString(); + } + + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////// INTERNAL CLASSES + // ///////////////////////////////////////////////// + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + protected class EmbeddedTcpBroker { + protected BrokerService brokerSvc; + protected int brokerNum; + protected String brokerName; + protected String brokerId; + protected int port; + protected String tcpUrl; + + public EmbeddedTcpBroker() throws Exception { + brokerSvc = new BrokerService(); + + synchronized (this.getClass()) { + brokerNum = Next_broker_num; + Next_broker_num++; + } + + brokerName = "broker" + brokerNum; + brokerId = "b" + brokerNum; + + brokerSvc.setBrokerName(brokerName); + brokerSvc.setBrokerId(brokerId); + brokerSvc.setPersistent(false); + brokerSvc.setUseJmx(false); + tcpUrl = brokerSvc.addConnector("tcp://localhost:0").getPublishableConnectString(); + } + + public Connection createConnection() throws URISyntaxException, JMSException { + Connection result; + + result = org.apache.activemq.ActiveMQConnection.makeConnection(this.tcpUrl); + + return result; + } + + public String getConnectionUrl() { + return this.tcpUrl; + } + + /** + * Create network connections to the given broker using the + * network-connector configuration of CORE brokers (e.g. + * core1.bus.dev1.coresys.tmcs) + * + * @param other + * @param duplex_f + */ + public void coreConnectTo(EmbeddedTcpBroker other, boolean duplex_f) throws Exception { + this.makeConnectionTo(other, duplex_f, true); + this.makeConnectionTo(other, duplex_f, false); + } + + public void start() throws Exception { + brokerSvc.start(); + } + + public void stop() throws Exception { + brokerSvc.stop(); + } + + /** + * Make one connection to the other embedded broker, of the specified + * type (queue or topic) using the standard CORE broker networking. + * + * @param other + * @param duplex_f + * @param queue_f + * @throws Exception + */ + protected void makeConnectionTo(EmbeddedTcpBroker other, boolean duplex_f, boolean queue_f) throws Exception { + NetworkConnector nw_conn; + String prefix; + ActiveMQDestination excl_dest; + ArrayList excludes; + + nw_conn = new DiscoveryNetworkConnector(new URI("static:(" + other.tcpUrl + ")")); + nw_conn.setDuplex(duplex_f); + + if (queue_f) + nw_conn.setConduitSubscriptions(false); + else + nw_conn.setConduitSubscriptions(true); + + nw_conn.setNetworkTTL(5); + nw_conn.setSuppressDuplicateQueueSubscriptions(true); + nw_conn.setDecreaseNetworkConsumerPriority(true); + nw_conn.setBridgeTempDestinations(true); + + if (queue_f) { + prefix = "queue"; + excl_dest = ActiveMQDestination.createDestination(">", ActiveMQDestination.QUEUE_TYPE); + } else { + prefix = "topic"; + excl_dest = ActiveMQDestination.createDestination(">", ActiveMQDestination.TOPIC_TYPE); + } + + excludes = new ArrayList(); + excludes.add(excl_dest); + nw_conn.setExcludedDestinations(excludes); + + if (duplex_f) + nw_conn.setName(this.brokerId + "<-" + prefix + "->" + other.brokerId); + else + nw_conn.setName(this.brokerId + "-" + prefix + "->" + other.brokerId); + + brokerSvc.addNetworkConnector(nw_conn); + } + } + + protected class MessageClient extends java.lang.Thread { + protected MessageConsumer msgCons; + protected boolean shutdownInd; + protected int expectedCount; + protected int lastSeq = 0; + protected int msgCount = 0; + protected boolean haveFirstSeq; + protected CountDownLatch shutdownLatch; + + public MessageClient(MessageConsumer cons, int num_to_expect) { + msgCons = cons; + expectedCount = (num_to_expect * (echoResponseFill + 1)); + shutdownLatch = new CountDownLatch(1); + } + + public void run() { + CountDownLatch latch; + + try { + synchronized (this) { + latch = shutdownLatch; + } + + shutdownInd = false; + processMessages(); + + latch.countDown(); + } catch (Exception exc) { + LOG.error("message client error", exc); + } + } + + public void waitShutdown(long timeout) { + CountDownLatch latch; + + try { + synchronized (this) { + latch = shutdownLatch; + } + + if (latch != null) + latch.await(timeout, TimeUnit.MILLISECONDS); + else + LOG.info("echo client shutdown: client does not appear to be active"); + } catch (InterruptedException int_exc) { + LOG.warn("wait for message client shutdown interrupted", int_exc); + } + } + + public boolean shutdown() { + boolean down_ind; + + if (!shutdownInd) { + shutdownInd = true; + } + + waitShutdown(200); + + synchronized (this) { + if ((shutdownLatch == null) || (shutdownLatch.getCount() == 0)) + down_ind = true; + else + down_ind = false; + } + + return down_ind; + } + + public int getNumMsgReceived() { + return msgCount; + } + + protected void processMessages() throws Exception { + Message in_msg; + + haveFirstSeq = false; + while ((!shutdownInd) && (!testError)) { + in_msg = msgCons.receive(100); + + if (in_msg != null) { + msgCount++; + checkMessage(in_msg); + } + } + } + + protected void checkMessage(Message in_msg) throws Exception { + int seq; + + LOG.debug("received message " + fmtMsgInfo(in_msg)); + + if (in_msg.propertyExists("SEQ")) { + seq = in_msg.getIntProperty("SEQ"); + + if ((haveFirstSeq) && (seq != (lastSeq + 1))) { + LOG.error("***ERROR*** incorrect sequence number; expected " + Integer.toString(lastSeq + 1) + " but have " + Integer.toString(seq)); + + testError = true; + } + + lastSeq = seq; + + if (msgCount > expectedCount) { + LOG.warn("*** have more messages than expected; have " + msgCount + "; expect " + expectedCount); + + testError = true; + } + } + + if (in_msg.propertyExists("end-of-response")) { + LOG.trace("received end-of-response message"); + shutdownInd = true; + } + } + } + + protected class EchoService extends java.lang.Thread { + protected String destName; + protected Connection jmsConn; + protected Session sess; + protected MessageConsumer msg_cons; + protected boolean Shutdown_ind; + + protected Destination req_dest; + protected Destination resp_dest; + protected MessageProducer msg_prod; + + protected CountDownLatch waitShutdown; + + public EchoService(String dest, Connection broker_conn) throws Exception { + destName = dest; + jmsConn = broker_conn; + + Shutdown_ind = false; + + sess = jmsConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + req_dest = sess.createQueue(destName); + msg_cons = sess.createConsumer(req_dest); + + jmsConn.start(); + + waitShutdown = new CountDownLatch(1); + } + + public EchoService(String dest, String broker_url) throws Exception { + this(dest, ActiveMQConnection.makeConnection(broker_url)); + } + + public void run() { + Message req; + + try { + LOG.info("STARTING ECHO SERVICE"); + + while (!Shutdown_ind) { + req = msg_cons.receive(100); + if (req != null) { + if (LOG.isDebugEnabled()) + LOG.debug("ECHO request message " + req.toString()); + + resp_dest = req.getJMSReplyTo(); + if (resp_dest != null) { + msg_prod = sess.createProducer(resp_dest); + msg_prod.send(req); + msg_prod.close(); + msg_prod = null; + } else { + LOG.warn("invalid request: no reply-to destination given"); + } + } + } + } catch (Exception ex) { + LOG.error(null, ex); + } finally { + LOG.info("shutting down test echo service"); + + try { + jmsConn.stop(); + } catch (javax.jms.JMSException jms_exc) { + LOG.warn("error on shutting down JMS connection", jms_exc); + } + + synchronized (this) { + waitShutdown.countDown(); + } + } + } + + /** + * Shut down the service, waiting up to 3 seconds for the service to + * terminate. + */ + public void shutdown() { + CountDownLatch wait_l; + + synchronized (this) { + wait_l = waitShutdown; + } + + Shutdown_ind = true; + + try { + if (wait_l != null) { + if (wait_l.await(3000, TimeUnit.MILLISECONDS)) { + LOG.info("echo service shutdown complete"); + } else { + LOG.warn("timeout waiting for echo service shutdown"); + } + } else { + LOG.info("echo service shutdown: service does not appear to be active"); + } + } catch (InterruptedException int_exc) { + LOG.warn("interrupted while waiting for echo service shutdown"); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3324Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3324Test.java new file mode 100644 index 0000000000..a1e9b93141 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3324Test.java @@ -0,0 +1,148 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.virtual.MirroredQueue; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3324Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3324Test.class); + + private static final String bindAddress = "tcp://0.0.0.0:0"; + private BrokerService broker; + private ActiveMQConnectionFactory cf; + + private static final int MESSAGE_COUNT = 100; + + @Before + public void setUp() throws Exception { + broker = this.createBroker(); + String address = broker.getTransportConnectors().get(0).getPublishableConnectString(); + broker.start(); + broker.waitUntilStarted(); + + cf = new ActiveMQConnectionFactory(address); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test + public void testTempMessageConsumedAdvisoryConnectionClose() throws Exception { + + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + final TemporaryQueue queue = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(queue); + + final Topic advisoryTopic = AdvisorySupport.getMessageConsumedAdvisoryTopic((ActiveMQDestination) queue); + + MessageConsumer advisoryConsumer = session.createConsumer(advisoryTopic); + MessageProducer producer = session.createProducer(queue); + + // send lots of messages to the tempQueue + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = session.createBytesMessage(); + m.writeBytes(new byte[1024]); + producer.send(m); + } + + // consume one message from tempQueue + Message msg = consumer.receive(5000); + assertNotNull(msg); + + // check one advisory message has produced on the advisoryTopic + Message advCmsg = advisoryConsumer.receive(5000); + assertNotNull(advCmsg); + + connection.close(); + LOG.debug("Connection closed, destinations should now become inactive."); + + assertTrue("The destination " + advisoryTopic + "was not removed. ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker.getAdminView().getTopics().length == 0; + } + })); + + assertTrue("The destination " + queue + " was not removed. ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker.getAdminView().getTemporaryQueues().length == 0; + } + })); + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseMirroredQueues(true); + answer.setPersistent(false); + answer.setSchedulePeriodForDestinationPurge(1000); + + PolicyEntry entry = new PolicyEntry(); + entry.setGcInactiveDestinations(true); + entry.setInactiveTimoutBeforeGC(2000); + entry.setProducerFlowControl(true); + entry.setAdvisoryForConsumed(true); + entry.setAdvisoryForFastProducers(true); + entry.setAdvisoryForDelivery(true); + PolicyMap map = new PolicyMap(); + map.setDefaultEntry(entry); + + MirroredQueue mirrorQ = new MirroredQueue(); + mirrorQ.setCopyMessage(true); + DestinationInterceptor[] destinationInterceptors = new DestinationInterceptor[]{mirrorQ}; + answer.setDestinationInterceptors(destinationInterceptors); + + answer.setDestinationPolicy(map); + answer.addConnector(bindAddress); + + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3352Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3352Test.java new file mode 100644 index 0000000000..aa84d2d541 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3352Test.java @@ -0,0 +1,75 @@ +/** + * 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.bugs; + +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ3352Test +{ + TransportConnector connector; + BrokerService brokerService; + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + connector = brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.start(); + } + + @After + public void stopBroker() throws Exception { + brokerService.stop(); + } + + @Test + public void verifyEnqueueLargeNumWithStateTracker() throws Exception { + String url = "failover:(" + connector.getPublishableConnectString() + ")?jms.useAsyncSend=true&trackMessages=true&maxCacheSize=131072"; + + ActiveMQConnection conn = (ActiveMQConnection)new ActiveMQConnectionFactory(url).createConnection(null, null); + + Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(session.createQueue("EVENTQ")); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.setDisableMessageID(true); + producer.setDisableMessageTimestamp(true); + + StringBuffer buffer = new StringBuffer(); + for (int i=0;i<1024;i++) + { + buffer.append(String.valueOf(Math.random())); + } + String payload = buffer.toString(); + + for (int i=0; i<10000; i++) { + StringBuffer buff = new StringBuffer("x"); + buff.append(payload); + producer.send(session.createTextMessage(buff.toString())); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3405Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3405Test.java new file mode 100644 index 0000000000..9711d06361 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3405Test.java @@ -0,0 +1,280 @@ +/** + * 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.bugs; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3405Test extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(AMQ3405Test.class); + + private Connection connection; + private Session session; + private MessageConsumer consumer; + private MessageProducer producer; + private int deliveryMode = DeliveryMode.PERSISTENT; + private Destination dlqDestination; + private MessageConsumer dlqConsumer; + private BrokerService broker; + + private int messageCount; + private Destination destination; + private int rollbackCount; + private Session dlqSession; + private final Error[] error = new Error[1]; + private boolean topic = true; + private boolean durableSubscriber = true; + + public void testTransientTopicMessage() throws Exception { + topic = true; + deliveryMode = DeliveryMode.NON_PERSISTENT; + durableSubscriber = true; + doTest(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + PolicyEntry policy = new PolicyEntry(); + DeadLetterStrategy defaultDeadLetterStrategy = policy.getDeadLetterStrategy(); + if(defaultDeadLetterStrategy!=null) { + defaultDeadLetterStrategy.setProcessNonPersistent(true); + } + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + return broker; + } + + protected void doTest() throws Exception { + messageCount = 200; + connection.start(); + + final QueueViewMBean dlqView = getProxyToDLQ(); + + ActiveMQConnection amqConnection = (ActiveMQConnection) connection; + rollbackCount = amqConnection.getRedeliveryPolicy().getMaximumRedeliveries() + 1; + LOG.info("Will redeliver messages: " + rollbackCount + " times"); + + makeConsumer(); + makeDlqConsumer(); + dlqConsumer.close(); + + sendMessages(); + + // now lets receive and rollback N times + int maxRollbacks = messageCount * rollbackCount; + + consumer.setMessageListener(new RollbackMessageListener(maxRollbacks, rollbackCount)); + + // We receive and rollback into the DLQ N times moving the DLQ messages back to their + // original Q to test that they are continually placed back in the DLQ. + for (int i = 0; i < 2; ++i) { + + assertTrue("DLQ was not filled as expected", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return dlqView.getQueueSize() == messageCount; + } + })); + + connection.stop(); + + assertEquals("DLQ should be full now.", messageCount, dlqView.getQueueSize()); + + String moveTo; + if (topic) { + moveTo = "topic://" + ((Topic) getDestination()).getTopicName(); + } else { + moveTo = "queue://" + ((Queue) getDestination()).getQueueName(); + } + + LOG.debug("Moving " + messageCount + " messages from ActiveMQ.DLQ to " + moveTo); + dlqView.moveMatchingMessagesTo("", moveTo); + + assertTrue("DLQ was not emptied as expected", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return dlqView.getQueueSize() == 0; + } + })); + + connection.start(); + } + } + + protected void makeConsumer() throws JMSException { + Destination destination = getDestination(); + LOG.info("Consuming from: " + destination); + if (durableSubscriber) { + consumer = session.createDurableSubscriber((Topic)destination, destination.toString()); + } else { + consumer = session.createConsumer(destination); + } + } + + protected void makeDlqConsumer() throws JMSException { + dlqDestination = createDlqDestination(); + + LOG.info("Consuming from dead letter on: " + dlqDestination); + dlqConsumer = dlqSession.createConsumer(dlqDestination); + } + + @Override + protected void setUp() throws Exception { + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + + connection = createConnection(); + connection.setClientID(createClientId()); + + session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + connection.start(); + + dlqSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + @Override + protected void tearDown() throws Exception { + dlqConsumer.close(); + dlqSession.close(); + session.close(); + + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + }; + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() + throws Exception { + ActiveMQConnectionFactory answer = super.createConnectionFactory(); + RedeliveryPolicy policy = new RedeliveryPolicy(); + policy.setMaximumRedeliveries(3); + policy.setBackOffMultiplier((short) 1); + policy.setRedeliveryDelay(0); + policy.setInitialRedeliveryDelay(0); + policy.setUseExponentialBackOff(false); + answer.setRedeliveryPolicy(policy); + return answer; + } + + protected void sendMessages() throws JMSException { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(getDestination()); + producer.setDeliveryMode(deliveryMode); + + LOG.info("Sending " + messageCount + " messages to: " + getDestination()); + for (int i = 0; i < messageCount; i++) { + Message message = createMessage(session, i); + producer.send(message); + } + } + + protected TextMessage createMessage(Session session, int i) throws JMSException { + return session.createTextMessage(getMessageText(i)); + } + + protected String getMessageText(int i) { + return "message: " + i; + } + + protected Destination createDlqDestination() { + return new ActiveMQQueue("ActiveMQ.DLQ"); + } + + private QueueViewMBean getProxyToDLQ() throws MalformedObjectNameException, JMSException { + ObjectName queueViewMBeanName = new ObjectName( + "org.apache.activemq:type=Broker,brokerName=localhost," + + "destinationType=Queue,destinationName=ActiveMQ.DLQ"); + QueueViewMBean proxy = (QueueViewMBean) broker.getManagementContext() + .newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true); + return proxy; + } + + protected Destination getDestination() { + if (destination == null) { + destination = createDestination(); + } + return destination; + } + + protected String createClientId() { + return toString(); + } + + class RollbackMessageListener implements MessageListener { + + final int maxRollbacks; + final int deliveryCount; + final AtomicInteger rollbacks = new AtomicInteger(); + + RollbackMessageListener(int c, int delvery) { + maxRollbacks = c; + deliveryCount = delvery; + } + + @Override + public void onMessage(Message message) { + try { + int expectedMessageId = rollbacks.get() / deliveryCount; + LOG.info("expecting messageId: " + expectedMessageId); + rollbacks.incrementAndGet(); + session.rollback(); + } catch (Throwable e) { + LOG.error("unexpected exception:" + e, e); + // propagating assertError to execution task will cause a hang + // at shutdown + if (e instanceof Error) { + error[0] = (Error) e; + } else { + fail("unexpected exception: " + e); + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3436Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3436Test.java new file mode 100644 index 0000000000..65e0783487 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3436Test.java @@ -0,0 +1,202 @@ +/** + * 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.bugs; + +import java.net.URI; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQMessageConsumer; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3436Test { + + protected static final Logger LOG = LoggerFactory.getLogger(AMQ3436Test.class); + + private BrokerService broker; + private PersistenceAdapter adapter; + private boolean useCache = true; + private boolean prioritizeMessages = true; + + protected PersistenceAdapter createPersistenceAdapter(boolean delete) throws Exception { + KahaDBPersistenceAdapter adapter = new KahaDBPersistenceAdapter(); + adapter.setConcurrentStoreAndDispatchQueues(false); + adapter.setConcurrentStoreAndDispatchTopics(false); + adapter.deleteAllMessages(); + return adapter; + } + + @Before + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setBrokerName("priorityTest"); + broker.setAdvisorySupport(false); + broker.setUseJmx(false); + adapter = createPersistenceAdapter(true); + broker.setPersistenceAdapter(adapter); + PolicyEntry policy = new PolicyEntry(); + policy.setPrioritizedMessages(prioritizeMessages); + policy.setUseCache(useCache); + policy.setProducerFlowControl(false); + PolicyMap policyMap = new PolicyMap(); + policyMap.put(new ActiveMQQueue("TEST"), policy); + + // do not process expired for one test + PolicyEntry ignoreExpired = new PolicyEntry(); + SharedDeadLetterStrategy ignoreExpiredStrategy = new SharedDeadLetterStrategy(); + ignoreExpiredStrategy.setProcessExpired(false); + ignoreExpired.setDeadLetterStrategy(ignoreExpiredStrategy); + + broker.setDestinationPolicy(policyMap); + broker.start(); + broker.waitUntilStarted(); + } + + protected void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testPriorityWhenConsumerCreatedBeforeProduction() throws Exception { + + int messageCount = 200; + URI failoverUri = new URI("vm://priorityTest?jms.prefetchPolicy.all=1"); + + ActiveMQQueue dest = new ActiveMQQueue("TEST?consumer.dispatchAsync=false"); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(failoverUri); + cf.setDispatchAsync(false); + + // Create producer + ActiveMQConnection producerConnection = (ActiveMQConnection) cf.createConnection(); + producerConnection.setMessagePrioritySupported(true); + producerConnection.start(); + final Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = producerSession.createProducer(dest); + + ActiveMQMessageConsumer consumer; + + // Create consumer on separate connection + ActiveMQConnection consumerConnection = (ActiveMQConnection) cf.createConnection(); + consumerConnection.setMessagePrioritySupported(true); + consumerConnection.start(); + final ActiveMQSession consumerSession = (ActiveMQSession) consumerConnection.createSession(true, + Session.SESSION_TRANSACTED); + consumer = (ActiveMQMessageConsumer) consumerSession.createConsumer(dest); + + // Produce X number of messages with a session commit after each message + Random random = new Random(); + for (int i = 0; i < messageCount; ++i) { + + Message message = producerSession.createTextMessage("Test message #" + i); + producer.send(message, DeliveryMode.PERSISTENT, random.nextInt(10), 45*1000); + producerSession.commit(); + } + producer.close(); + + // *************************************************** + // If we create the consumer here instead of above, the + // the messages will be consumed in priority order + // *************************************************** + //consumer = (ActiveMQMessageConsumer) consumerSession.createConsumer(dest); + + // Consume all of the messages we produce using a listener. + // Don't exit until we get all the messages. + final CountDownLatch latch = new CountDownLatch(messageCount); + final StringBuffer failureMessage = new StringBuffer(); + consumer.setMessageListener(new MessageListener() { + int lowestPrioritySeen = 10; + + boolean firstMessage = true; + + public void onMessage(Message msg) { + try { + + int currentPriority = msg.getJMSPriority(); + LOG.debug(currentPriority + "<=" + lowestPrioritySeen); + + // Ignore the first message priority since it is prefetched + // and is out of order by design + if (firstMessage == true) { + firstMessage = false; + LOG.debug("Ignoring first message since it was prefetched"); + + } else { + + // Verify that we never see a priority higher than the + // lowest + // priority seen + if (lowestPrioritySeen > currentPriority) { + lowestPrioritySeen = currentPriority; + } + if (lowestPrioritySeen < currentPriority) { + failureMessage.append("Incorrect priority seen (Lowest Priority = " + lowestPrioritySeen + + " Current Priority = " + currentPriority + ")" + + System.getProperty("line.separator")); + } + } + + } catch (JMSException e) { + e.printStackTrace(); + } finally { + latch.countDown(); + LOG.debug("Messages remaining = " + latch.getCount()); + } + } + }); + + latch.await(); + consumer.close(); + + // Cleanup producer resources + producerSession.close(); + producerConnection.stop(); + producerConnection.close(); + + // Cleanup consumer resources + consumerSession.close(); + consumerConnection.stop(); + consumerConnection.close(); + + // Report the failure if found + if (failureMessage.length() > 0) { + Assert.fail(failureMessage.toString()); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3445Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3445Test.java new file mode 100644 index 0000000000..73035e2221 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3445Test.java @@ -0,0 +1,150 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ3445Test { + + private ConnectionFactory connectionFactory; + private BrokerService broker; + private String connectionUri; + + private final String queueName = "Consumer.MyApp.VirtualTopic.FOO"; + private final String topicName = "VirtualTopic.FOO"; + + @Before + public void startBroker() throws Exception { + createBroker(true); + } + + private void createBroker(boolean deleteMessages) throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(deleteMessages); + broker.setPersistenceAdapter(new JDBCPersistenceAdapter()); + broker.setAdvisorySupport(false); + broker.addConnector("tcp://0.0.0.0:0"); + broker.start(); + broker.waitUntilStarted(); + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + } + + private void restartBroker() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + + createBroker(false); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test + public void testJDBCRetiansDestinationAfterRestart() throws Exception { + + broker.getAdminView().addQueue(queueName); + broker.getAdminView().addTopic(topicName); + + assertTrue(findDestination(queueName, false)); + assertTrue(findDestination(topicName, true)); + + QueueViewMBean queue = getProxyToQueueViewMBean(); + assertEquals(0, queue.getQueueSize()); + + restartBroker(); + + assertTrue(findDestination(queueName, false)); + queue = getProxyToQueueViewMBean(); + assertEquals(0, queue.getQueueSize()); + + sendMessage(); + restartBroker(); + assertTrue(findDestination(queueName, false)); + + queue = getProxyToQueueViewMBean(); + assertEquals(1, queue.getQueueSize()); + sendMessage(); + assertEquals(2, queue.getQueueSize()); + + restartBroker(); + assertTrue(findDestination(queueName, false)); + queue = getProxyToQueueViewMBean(); + assertEquals(2, queue.getQueueSize()); + } + + private void sendMessage() throws Exception { + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createTopic(topicName)); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.send(session.createTextMessage("Testing")); + producer.close(); + connection.close(); + } + + private QueueViewMBean getProxyToQueueViewMBean() throws Exception { + ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq" + + ":destinationType=Queue,destinationName=" + queueName + + ",type=Broker,brokerName=localhost"); + QueueViewMBean proxy = (QueueViewMBean) broker.getManagementContext() + .newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true); + return proxy; + } + + private boolean findDestination(String name, boolean topic) throws Exception { + + ObjectName[] destinations; + + if (topic) { + destinations = broker.getAdminView().getTopics(); + } else { + destinations = broker.getAdminView().getQueues(); + } + + for (ObjectName destination : destinations) { + if (destination.toString().contains(name)) { + return true; + } + } + + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3454Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3454Test.java new file mode 100644 index 0000000000..99c12fc459 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3454Test.java @@ -0,0 +1,74 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3454Test extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ3454Test.class); + private static final int MESSAGES_COUNT = 10000; + + public void testSendWithLotsOfDestinations() throws Exception { + final BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.setDeleteAllMessagesOnStartup(true); + + broker.addConnector("tcp://localhost:0"); + + // populate a bunch of destinations, validate the impact on a call to send + ActiveMQDestination[] destinations = new ActiveMQDestination[MESSAGES_COUNT]; + for (int idx = 0; idx < MESSAGES_COUNT; ++idx) { + destinations[idx] = new ActiveMQQueue(getDestinationName() + "-" + idx); + } + broker.setDestinations(destinations); + broker.start(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getPublishableConnectString()); + final Connection connection = factory.createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(new ActiveMQQueue(getDestinationName())); + + long start = System.currentTimeMillis(); + for (int idx = 0; idx < MESSAGES_COUNT; ++idx) { + Message message = session.createTextMessage("" + idx); + producer.send(message); + } + LOG.info("Duration: " + (System.currentTimeMillis() - start) + " millis"); + producer.close(); + session.close(); + + } + + protected String getDestinationName() { + return getClass().getName() + "." + getName(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3465Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3465Test.java new file mode 100644 index 0000000000..bac3829bb0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3465Test.java @@ -0,0 +1,195 @@ +/** + * 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.bugs; + +import static org.junit.Assert.*; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.XAConnection; +import javax.jms.XAConnectionFactory; +import javax.jms.XASession; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQMessageProducer; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.ActiveMQXAConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ3465Test +{ + private final String xaDestinationName = "DestinationXA"; + private final String destinationName = "Destination"; + private BrokerService broker; + private String connectionUri; + private long txGenerator = System.currentTimeMillis(); + + private XAConnectionFactory xaConnectionFactory; + private ConnectionFactory connectionFactory; + + @Before + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://0.0.0.0:0"); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + xaConnectionFactory = new ActiveMQXAConnectionFactory(connectionUri); + } + + @After + public void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testMixedXAandNonXAorTXSessions() throws Exception { + + XAConnection xaConnection = xaConnectionFactory.createXAConnection(); + xaConnection.start(); + XASession session = xaConnection.createXASession(); + XAResource resource = session.getXAResource(); + Destination dest = new ActiveMQQueue(xaDestinationName); + + // publish a message + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + MessageProducer producer = session.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setText("Some Text"); + producer.send(message); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + session.close(); + + session = xaConnection.createXASession(); + MessageConsumer consumer = session.createConsumer(dest); + tid = createXid(); + resource = session.getXAResource(); + resource.start(tid, XAResource.TMNOFLAGS); + TextMessage receivedMessage = (TextMessage) consumer.receive(1000); + assertNotNull(receivedMessage); + assertEquals("Some Text", receivedMessage.getText()); + resource.end(tid, XAResource.TMSUCCESS); + + // Test that a normal session doesn't operate on XASession state. + Connection connection2 = connectionFactory.createConnection(); + connection2.start(); + ActiveMQSession session2 = (ActiveMQSession) connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + + if (session2.isTransacted()) { + session2.rollback(); + } + + session2.close(); + + resource.commit(tid, true); + } + + @Test + public void testMixedXAandNonXALocalTXSessions() throws Exception { + + XAConnection xaConnection = xaConnectionFactory.createXAConnection(); + xaConnection.start(); + XASession session = xaConnection.createXASession(); + XAResource resource = session.getXAResource(); + Destination dest = new ActiveMQQueue(xaDestinationName); + + // publish a message + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + MessageProducer producer = session.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setText("Some Text"); + producer.send(message); + resource.end(tid, XAResource.TMSUCCESS); + resource.commit(tid, true); + session.close(); + + session = xaConnection.createXASession(); + MessageConsumer consumer = session.createConsumer(dest); + tid = createXid(); + resource = session.getXAResource(); + resource.start(tid, XAResource.TMNOFLAGS); + TextMessage receivedMessage = (TextMessage) consumer.receive(1000); + assertNotNull(receivedMessage); + assertEquals("Some Text", receivedMessage.getText()); + resource.end(tid, XAResource.TMSUCCESS); + + // Test that a normal session doesn't operate on XASession state. + Connection connection2 = connectionFactory.createConnection(); + connection2.start(); + ActiveMQSession session2 = (ActiveMQSession) connection2.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = new ActiveMQQueue(destinationName); + ActiveMQMessageProducer producer2 = (ActiveMQMessageProducer) session2.createProducer(destination); + producer2.send(session2.createTextMessage("Local-TX")); + + if (session2.isTransacted()) { + session2.rollback(); + } + + session2.close(); + + resource.commit(tid, true); + } + + public Xid createXid() throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + os.writeLong(++txGenerator); + os.close(); + final byte[] bs = baos.toByteArray(); + + return new Xid() { + public int getFormatId() { + return 86; + } + + public byte[] getGlobalTransactionId() { + return bs; + } + + public byte[] getBranchQualifier() { + return bs; + } + }; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3529Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3529Test.java new file mode 100644 index 0000000000..7e8b9d0116 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3529Test.java @@ -0,0 +1,177 @@ +/** + * 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.bugs; + +import java.util.Properties; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3529Test { + + private static Logger LOG = LoggerFactory.getLogger(AMQ3529Test.class); + + private ConnectionFactory connectionFactory; + private Connection connection; + private Session session; + private BrokerService broker; + private String connectionUri; + private MessageConsumer consumer; + private Context ctx = null; + + @Before + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://0.0.0.0:0"); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + } + + @After + public void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test(timeout = 60000) + public void testInterruptionAffects() throws Exception { + ThreadGroup tg = new ThreadGroup("tg"); + + assertEquals(0, tg.activeCount()); + + Thread client = new Thread(tg, "client") { + + @Override + public void run() { + try { + connection = connectionFactory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + assertNotNull(session); + + Properties props = new Properties(); + props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + props.setProperty(Context.PROVIDER_URL, "tcp://0.0.0.0:0"); + ctx = null; + try { + ctx = new InitialContext(props); + } catch (NoClassDefFoundError e) { + throw new NamingException(e.toString()); + } catch (Exception e) { + throw new NamingException(e.toString()); + } + Destination destination = (Destination) ctx.lookup("dynamicTopics/example.C"); + consumer = session.createConsumer(destination); + consumer.receive(10000); + } catch (Exception e) { + // Expect an exception here from the interrupt. + } finally { + // next line is the nature of the test, if I remove this + // line, everything works OK + try { + consumer.close(); + } catch (JMSException e) { + fail("Consumer Close failed with" + e.getMessage()); + } + try { + session.close(); + } catch (JMSException e) { + fail("Session Close failed with" + e.getMessage()); + } + try { + connection.close(); + } catch (JMSException e) { + fail("Connection Close failed with" + e.getMessage()); + } + try { + ctx.close(); + } catch (Exception e) { + fail("Connection Close failed with" + e.getMessage()); + } + } + } + }; + client.start(); + Thread.sleep(5000); + client.interrupt(); + client.join(); + Thread.sleep(2000); + Thread[] remainThreads = new Thread[tg.activeCount()]; + tg.enumerate(remainThreads); + for (Thread t : remainThreads) { + if (t.isAlive() && !t.isDaemon()) + fail("Remaining thread: " + t.toString()); + } + + ThreadGroup root = Thread.currentThread().getThreadGroup().getParent(); + while (root.getParent() != null) { + root = root.getParent(); + } + visit(root, 0); + } + + // This method recursively visits all thread groups under `group'. + public static void visit(ThreadGroup group, int level) { + // Get threads in `group' + int numThreads = group.activeCount(); + Thread[] threads = new Thread[numThreads * 2]; + numThreads = group.enumerate(threads, false); + + // Enumerate each thread in `group' + for (int i = 0; i < numThreads; i++) { + // Get thread + Thread thread = threads[i]; + LOG.debug("Thread:" + thread.getName() + " is still running"); + } + + // Get thread subgroups of `group' + int numGroups = group.activeGroupCount(); + ThreadGroup[] groups = new ThreadGroup[numGroups * 2]; + numGroups = group.enumerate(groups, false); + + // Recursively visit each subgroup + for (int i = 0; i < numGroups; i++) { + visit(groups[i], level + 1); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3537Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3537Test.java new file mode 100644 index 0000000000..fe8e3fd405 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3537Test.java @@ -0,0 +1,104 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq.util.ClassLoadingAwareObjectInputStream; +import org.junit.Before; +import org.junit.Test; + +/** + * Quick port to java to support AMQ build. + * + * This test demonstrates the classloader problem in the + * ClassLoadingAwareObjectInputStream impl. If the first interface in the proxy + * interfaces list is JDK and there are any subsequent interfaces that are NOT + * JDK interfaces the ClassLoadingAwareObjectInputStream will ignore their + * respective classloaders and cause the Proxy to throw an + * IllegalArgumentException because the core JDK classloader can't load the + * interfaces that are not JDK interfaces. + * + * See AMQ-3537 + * + * @author jason.yankus + * + */ +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class AMQ3537Test implements InvocationHandler, Serializable { + + private static final long serialVersionUID = 1L; + + /** + * If the first and second element in this array are swapped, the test will + * fail. + */ + public static final Class[] TEST_CLASSES = new Class[] { List.class, NonJDKList.class, Serializable.class }; + + /** Underlying list */ + private final List l = new ArrayList(); + + @Before + public void setUp() throws Exception { + l.add("foo"); + } + + @Test + public void testDeserializeProxy() throws Exception { + // create the proxy + List proxy = (List) java.lang.reflect.Proxy.newProxyInstance(this.getClass().getClassLoader(), TEST_CLASSES, this); + + // serialize it + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(proxy); + byte[] serializedProxy = baos.toByteArray(); + oos.close(); + baos.close(); + + // deserialize the proxy + ClassLoadingAwareObjectInputStream claois = + new ClassLoadingAwareObjectInputStream(new ByteArrayInputStream(serializedProxy)); + + // this is where it fails due to the rudimentary classloader selection + // in ClassLoadingAwareObjectInputStream + List deserializedProxy = (List) claois.readObject(); + + claois.close(); + + // assert the invocation worked + assertEquals("foo", deserializedProxy.get(0)); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return method.invoke(l, args); + } + + public interface NonJDKList { + int size(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3567Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3567Test.java new file mode 100644 index 0000000000..b4ce82fce1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3567Test.java @@ -0,0 +1,208 @@ +/** + * 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.bugs; + +import static org.junit.Assert.fail; + +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.Level; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Claudio Corsi + * + */ +public class AMQ3567Test { + + private static Logger logger = LoggerFactory.getLogger(AMQ3567Test.class); + + private ActiveMQConnectionFactory factory; + private Connection connection; + private Session sessionWithListener, session; + private Queue destination; + private MessageConsumer consumer; + private Thread thread; + private BrokerService broker; + private String connectionUri; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + startBroker(); + initializeConsumer(); + startConsumer(); + } + + @Test + public void runTest() throws Exception { + produceSingleMessage(); + org.apache.log4j.Logger log4jLogger = org.apache.log4j.Logger.getLogger("org.apache.activemq.util.ServiceSupport"); + final AtomicBoolean failed = new AtomicBoolean(false); + + Appender appender = new DefaultTestAppender() { + @Override + public void doAppend(LoggingEvent event) { + if (event.getThrowableInformation() != null) { + if (event.getThrowableInformation().getThrowable() instanceof InterruptedException) { + InterruptedException ie = (InterruptedException)event.getThrowableInformation().getThrowable(); + if (ie.getMessage().startsWith("Could not stop service:")) { + logger.info("Received an interrupted exception : ", ie); + failed.set(true); + } + } + } + } + }; + log4jLogger.addAppender(appender); + + Level level = log4jLogger.getLevel(); + log4jLogger.setLevel(Level.DEBUG); + + try { + stopConsumer(); + stopBroker(); + if (failed.get()) { + fail("An Interrupt exception was generated"); + } + + } finally { + log4jLogger.setLevel(level); + log4jLogger.removeAppender(appender); + } + } + + private void startBroker() throws Exception { + broker = new BrokerService(); + broker.setDataDirectory("target/data"); + connectionUri = broker.addConnector("tcp://localhost:0?wireFormat.maxInactivityDuration=30000&transport.closeAsync=false&transport.threadName&soTimeout=60000&transport.keepAlive=false&transport.useInactivityMonitor=false").getPublishableConnectString(); + broker.start(true); + broker.waitUntilStarted(); + } + + private void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + private void initializeConsumer() throws JMSException { + logger.info("Initializing the consumer messagor that will just not do anything...."); + factory = new ActiveMQConnectionFactory(); + factory.setBrokerURL("failover:("+connectionUri+"?wireFormat.maxInactivityDuration=30000&keepAlive=true&soTimeout=60000)?jms.watchTopicAdvisories=false&jms.useAsyncSend=false&jms.dispatchAsync=true&jms.producerWindowSize=10485760&jms.copyMessageOnSend=false&jms.disableTimeStampsByDefault=true&InitialReconnectDelay=1000&maxReconnectDelay=10000&maxReconnectAttempts=400&useExponentialBackOff=true"); + connection = factory.createConnection(); + connection.start(); + sessionWithListener = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = sessionWithListener.createQueue("EMPTY.QUEUE"); + } + + private void startConsumer() throws Exception { + logger.info("Starting the consumer"); + consumer = sessionWithListener.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + logger.info("Received a message: " + message); + } + + }); + + thread = new Thread(new Runnable() { + + private Session session; + + @Override + public void run() { + try { + destination = session.createQueue("EMPTY.QUEUE"); + MessageConsumer consumer = session.createConsumer(destination); + for (int cnt = 0; cnt < 2; cnt++) { + Message message = consumer.receive(50000); + logger.info("Received message: " + message); + } + } catch (JMSException e) { + logger.debug("Received an exception while processing messages", e); + } finally { + try { + session.close(); + } catch (JMSException e) { + logger.debug("Received an exception while closing session", e); + } + } + } + + public Runnable setSession(Session session) { + this.session = session; + return this; + } + + }.setSession(session)) { + { + start(); + } + }; + } + + private void stopConsumer() throws JMSException { + logger.info("Stopping the consumer"); + try { + thread.join(); + } catch (InterruptedException e) { + logger.debug("Received an exception while waiting for thread to complete", e); + } + if (sessionWithListener != null) { + sessionWithListener.close(); + } + if (connection != null) { + connection.stop(); + } + } + + private void produceSingleMessage() throws JMSException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(); + factory.setBrokerURL(connectionUri); + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue("EMPTY.QUEUE"); + MessageProducer producer = session.createProducer(destination); + producer.send(session.createTextMessage("Single Message")); + producer.close(); + session.close(); + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3622Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3622Test.java new file mode 100644 index 0000000000..e08279cce8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3622Test.java @@ -0,0 +1,109 @@ +/** + * 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.bugs; + +import static org.junit.Assert.fail; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.FilePendingSubscriberMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.LastImageSubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.transport.stomp.Stomp; +import org.apache.activemq.transport.stomp.StompConnection; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ3622Test { + + protected BrokerService broker; + protected AtomicBoolean failed = new AtomicBoolean(false); + protected String connectionUri; + protected Appender appender = new DefaultTestAppender() { + + @Override + public void doAppend(LoggingEvent event) { + System.err.println(event.getMessage()); + if (event.getThrowableInformation() != null) { + if (event.getThrowableInformation().getThrowable() instanceof NullPointerException) { + failed.set(true); + } + } + } + }; + + @Before + public void before() throws Exception { + Logger.getRootLogger().addAppender(appender); + + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(true); + PolicyEntry policy = new PolicyEntry(); + policy.setTopic(">"); + policy.setProducerFlowControl(false); + policy.setMemoryLimit(1 * 1024 * 1024); + policy.setPendingSubscriberPolicy(new FilePendingSubscriberMessageStoragePolicy()); + policy.setSubscriptionRecoveryPolicy(new LastImageSubscriptionRecoveryPolicy()); + policy.setExpireMessagesPeriod(500); + List entries = new ArrayList(); + + entries.add(policy); + PolicyMap pMap = new PolicyMap(); + pMap.setPolicyEntries(entries); + broker.setDestinationPolicy(pMap); + + connectionUri = broker.addConnector("stomp://localhost:0").getPublishableConnectString(); + + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void after() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + Logger.getRootLogger().removeAppender(appender); + } + + @Test + public void go() throws Exception { + StompConnection connection = new StompConnection(); + Integer port = Integer.parseInt(connectionUri.split(":")[2]); + connection.open("localhost", port); + connection.connect("", ""); + connection.subscribe("/topic/foobar", Stomp.Headers.Subscribe.AckModeValues.CLIENT); + connection.disconnect(); + Thread.sleep(1000); + + if (failed.get()) { + fail("Received NullPointerException"); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3625Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3625Test.java new file mode 100644 index 0000000000..a386202ef0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3625Test.java @@ -0,0 +1,111 @@ +/** + * 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.bugs; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * + */ + +public class AMQ3625Test { + + protected BrokerService broker1; + protected BrokerService broker2; + + protected AtomicBoolean authenticationFailed = new AtomicBoolean(false); + protected AtomicBoolean gotNPE = new AtomicBoolean(false); + + protected String java_security_auth_login_config = "java.security.auth.login.config"; + protected String xbean = "xbean:"; + protected String base = "src/test/resources/org/apache/activemq/bugs/amq3625"; + protected String conf = "conf"; + protected String keys = "keys"; + protected String JaasStompSSLBroker1_xml = "JaasStompSSLBroker1.xml"; + protected String JaasStompSSLBroker2_xml = "JaasStompSSLBroker2.xml"; + + protected String oldLoginConf = null; + + @Before + public void before() throws Exception { + if (System.getProperty(java_security_auth_login_config) != null) { + oldLoginConf = System.getProperty(java_security_auth_login_config); + } + System.setProperty(java_security_auth_login_config, base + "/" + conf + "/" + "login.config"); + broker1 = BrokerFactory.createBroker(xbean + base + "/" + conf + "/" + JaasStompSSLBroker1_xml); + broker2 = BrokerFactory.createBroker(xbean + base + "/" + conf + "/" + JaasStompSSLBroker2_xml); + + broker1.start(); + broker1.waitUntilStarted(); + broker2.start(); + broker2.waitUntilStarted(); + } + + @After + public void after() throws Exception { + broker1.stop(); + broker2.stop(); + + if (oldLoginConf != null) { + System.setProperty(java_security_auth_login_config, oldLoginConf); + } + } + + @Test + public void go() throws Exception { + Appender appender = new DefaultTestAppender() { + @Override + public void doAppend(LoggingEvent event) { + if (event.getThrowableInformation() != null) { + Throwable t = event.getThrowableInformation().getThrowable(); + if (t instanceof SecurityException) { + authenticationFailed.set(true); + } + if (t instanceof NullPointerException) { + gotNPE.set(true); + } + } + } + }; + Logger.getRootLogger().addAppender(appender); + + String connectURI = broker1.getConnectorByName("openwire").getConnectUri().toString(); + connectURI = connectURI.replace("?needClientAuth=true", ""); + broker2.addNetworkConnector("static:(" + connectURI + ")").start(); + + Thread.sleep(10 * 1000); + + Logger.getRootLogger().removeAppender(appender); + + assertTrue(authenticationFailed.get()); + assertFalse(gotNPE.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3674Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3674Test.java new file mode 100644 index 0000000000..47ab75481d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3674Test.java @@ -0,0 +1,120 @@ +/** + * 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.bugs; + +import static org.junit.Assert.*; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3674Test { + + private static Logger LOG = LoggerFactory.getLogger(AMQ3674Test.class); + + private final static int deliveryMode = DeliveryMode.NON_PERSISTENT; + private final static ActiveMQTopic destination = new ActiveMQTopic("XYZ"); + + private ActiveMQConnectionFactory factory; + private BrokerService broker; + + @Test + public void removeSubscription() throws Exception { + + final Connection producerConnection = factory.createConnection(); + producerConnection.start(); + final Connection consumerConnection = factory.createConnection(); + + consumerConnection.setClientID("subscriber1"); + Session consumerMQSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + TopicSubscriber activeConsumer = (TopicSubscriber) consumerMQSession.createDurableSubscriber(destination, "myTopic"); + consumerConnection.start(); + + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + final BrokerView brokerView = broker.getAdminView(); + + assertEquals(1, brokerView.getDurableTopicSubscribers().length); + + LOG.info("Current Durable Topic Subscriptions: " + brokerView.getDurableTopicSubscribers().length); + + try { + brokerView.destroyDurableSubscriber("subscriber1", "myTopic"); + fail("Expected Exception for Durable consumer is in use"); + } catch(Exception e) { + LOG.info("Recieved expected exception: " + e.getMessage()); + } + + LOG.info("Current Durable Topic Subscriptions: " + brokerView.getDurableTopicSubscribers().length); + + assertEquals(1, brokerView.getDurableTopicSubscribers().length); + + activeConsumer.close(); + consumerConnection.stop(); + + assertTrue("The subscription should be in the inactive state.", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return brokerView.getInactiveDurableTopicSubscribers().length == 1; + } + })); + + try { + brokerView.destroyDurableSubscriber("subscriber1", "myTopic"); + } finally { + producer.close(); + producerConnection.close(); + } + } + + @Before + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.setDeleteAllMessagesOnStartup(true); + TransportConnector connector = broker.addConnector("tcp://localhost:0"); + broker.start(); + + factory = new ActiveMQConnectionFactory(connector.getPublishableConnectString()); + factory.setAlwaysSyncSend(true); + factory.setDispatchAsync(false); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3675Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3675Test.java new file mode 100644 index 0000000000..c8e4bf4759 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3675Test.java @@ -0,0 +1,161 @@ +/** + * 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.bugs; + +import static org.junit.Assert.*; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TopicSubscriber; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.broker.jmx.TopicViewMBean; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3675Test { + + private static Logger LOG = LoggerFactory.getLogger(AMQ3675Test.class); + + private final static int deliveryMode = DeliveryMode.NON_PERSISTENT; + private final static ActiveMQTopic destination = new ActiveMQTopic("XYZ"); + + private ActiveMQConnectionFactory factory; + private BrokerService broker; + + public TopicViewMBean getTopicView() throws Exception { + ObjectName destinationName = broker.getAdminView().getTopics()[0]; + TopicViewMBean topicView = (TopicViewMBean) broker.getManagementContext().newProxyInstance(destinationName, TopicViewMBean.class, true); + return topicView; + } + + @Test + public void countConsumers() throws Exception { + + final Connection producerConnection = factory.createConnection(); + producerConnection.start(); + final Connection consumerConnection = factory.createConnection(); + + consumerConnection.setClientID("subscriber1"); + Session consumerMQSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + TopicSubscriber consumer = consumerMQSession.createDurableSubscriber(destination, "myTopic"); + consumerConnection.start(); + + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + final BrokerView brokerView = broker.getAdminView(); + final TopicViewMBean topicView = getTopicView(); + + assertTrue("Should have one consumer on topic: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return topicView.getConsumerCount() == 1; + } + })); + + consumer.close(); + + assertTrue("Durable consumer should now be inactive.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return brokerView.getInactiveDurableTopicSubscribers().length == 1; + } + })); + + try { + brokerView.removeTopic(destination.getTopicName()); + } catch (Exception e1) { + fail("Unable to remove destination:" + destination.getPhysicalName()); + } + + assertTrue("Should have no topics on the broker", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return brokerView.getTopics().length == 0; + } + })); + + try { + brokerView.destroyDurableSubscriber("subscriber1", "myTopic"); + } catch(Exception e) { + fail("Exception not expected when attempting to delete Durable consumer."); + } + + assertTrue("Should be no durable consumers active or inactive.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return brokerView.getInactiveDurableTopicSubscribers().length == 0 && + brokerView.getDurableTopicSubscribers().length == 0; + } + })); + + consumer = consumerMQSession.createDurableSubscriber(destination, "myTopic"); + + consumer.close(); + + assertTrue("Should be one consumer on the Topic.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("Number of inactive consumers: " + brokerView.getInactiveDurableTopicSubscribers().length); + return brokerView.getInactiveDurableTopicSubscribers().length == 1; + } + })); + + final TopicViewMBean recreatedTopicView = getTopicView(); + + assertTrue("Should have one consumer on topic: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return recreatedTopicView.getConsumerCount() == 1; + } + })); + } + + @Before + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + TransportConnector connector = broker.addConnector("tcp://localhost:0"); + broker.start(); + + factory = new ActiveMQConnectionFactory(connector.getPublishableConnectString()); + factory.setAlwaysSyncSend(true); + factory.setDispatchAsync(false); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3678Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3678Test.java new file mode 100644 index 0000000000..3c79fcff79 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3678Test.java @@ -0,0 +1,220 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.net.ServerSocket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQTopicSubscriber; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.fail; + + +public class AMQ3678Test implements MessageListener { + + public int deliveryMode = DeliveryMode.NON_PERSISTENT; + + + private BrokerService broker; + + AtomicInteger messagesSent = new AtomicInteger(0); + AtomicInteger messagesReceived = new AtomicInteger(0); + + ActiveMQTopic destination = new ActiveMQTopic("XYZ"); + + int port; + int jmxport; + + + final CountDownLatch latch = new CountDownLatch(2); + + + public static void main(String[] args) throws Exception { + + } + + + public static int findFreePort() throws IOException { + ServerSocket socket = null; + + try { + // 0 is open a socket on any free port + socket = new ServerSocket(0); + return socket.getLocalPort(); + } finally { + if (socket != null) { + socket.close(); + } + } + } + + + @Test + public void countConsumers() throws JMSException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:" + port); + factory.setAlwaysSyncSend(true); + factory.setDispatchAsync(false); + + final Connection producerConnection = factory.createConnection(); + producerConnection.start(); + + final Connection consumerConnection = factory.createConnection(); + + consumerConnection.setClientID("subscriber1"); + Session consumerMQSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + ActiveMQTopicSubscriber activeConsumer = (ActiveMQTopicSubscriber) consumerMQSession.createDurableSubscriber(destination, "myTopic?consumer.prefetchSize=1"); + + activeConsumer.setMessageListener(this); + + consumerConnection.start(); + + + final Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = producerSession.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + Thread t = new Thread(new Runnable() { + + private boolean done = false; + + public void run() { + while (!done) { + if (messagesSent.get() == 50) { + try { + broker.getAdminView().removeTopic(destination.getTopicName()); + } catch (Exception e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + System.err.flush(); + fail("Unable to remove destination:" + + destination.getPhysicalName()); + } + } + + try { + producer.send(producerSession.createTextMessage()); + int val = messagesSent.incrementAndGet(); + + System.out.println("sent message (" + val + ")"); + System.out.flush(); + + if (val == 100) { + done = true; + latch.countDown(); + producer.close(); + producerSession.close(); + + } + } catch (JMSException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + }); + + t.start(); + + try { + if (!latch.await(10, TimeUnit.SECONDS)) { + fail("did not receive all the messages"); + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + fail("did not receive all the messages, exception waiting for latch"); + e.printStackTrace(); + } + + +// + + + } + + @Before + public void setUp() throws Exception { + + try { + port = findFreePort(); + jmxport = findFreePort(); + } catch (Exception e) { + fail("Unable to obtain a free port on which to start the broker"); + } + + System.out.println("Starting broker"); + System.out.flush(); + broker = new BrokerService(); + broker.setPersistent(false); + ManagementContext ctx = new ManagementContext(ManagementFactory.getPlatformMBeanServer()); + ctx.setConnectorPort(jmxport); + broker.setManagementContext(ctx); + broker.setUseJmx(true); +// broker.setAdvisorySupport(false); +// broker.setDeleteAllMessagesOnStartup(true); + + broker.addConnector("tcp://localhost:" + port).setName("Default"); + broker.start(); + + + System.out.println("End of Broker Setup"); + System.out.flush(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } + + + @Override + public void onMessage(Message message) { + try { + message.acknowledge(); + int val = messagesReceived.incrementAndGet(); + System.out.println("received message (" + val + ")"); + System.out.flush(); + if (messagesReceived.get() == 100) { + latch.countDown(); + } + } catch (JMSException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3732Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3732Test.java new file mode 100644 index 0000000000..601901be83 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3732Test.java @@ -0,0 +1,174 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; + +import java.util.Random; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3732Test { + + private static Logger LOG = LoggerFactory.getLogger(AMQ3732Test.class); + + private ActiveMQConnectionFactory connectionFactory; + private Connection connection; + private Session session; + private BrokerService broker; + private String connectionUri; + + private final Random pause = new Random(); + private final long NUM_MESSAGES = 25000; + private final AtomicLong totalConsumed = new AtomicLong(); + + @Before + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://0.0.0.0:0"); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + connectionFactory.getPrefetchPolicy().setAll(0); + } + + @After + public void stopBroker() throws Exception { + connection.close(); + + broker.stop(); + broker.waitUntilStopped(); + } + + @Test(timeout = 1200000) + public void testInterruptionAffects() throws Exception { + + connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE); + + Queue queue = session.createQueue("AMQ3732Test"); + + final LinkedBlockingQueue workQueue = new LinkedBlockingQueue(); + + final MessageConsumer consumer1 = session.createConsumer(queue); + final MessageConsumer consumer2 = session.createConsumer(queue); + final MessageProducer producer = session.createProducer(queue); + + Thread consumer1Thread = new Thread(new Runnable() { + + @Override + public void run() { + try { + while (totalConsumed.get() < NUM_MESSAGES) { + Message message = consumer1.receiveNoWait(); + if (message != null) { + workQueue.add(message); + } + } + } catch(Exception e) { + LOG.error("Caught an unexpected error: ", e); + } + } + }); + consumer1Thread.start(); + + Thread consumer2Thread = new Thread(new Runnable() { + + @Override + public void run() { + try { + while (totalConsumed.get() < NUM_MESSAGES) { + Message message = consumer2.receive(50); + if (message != null) { + workQueue.add(message); + } + } + } catch(Exception e) { + LOG.error("Caught an unexpected error: ", e); + } + } + }); + consumer2Thread.start(); + + Thread producerThread = new Thread(new Runnable() { + + @Override + public void run() { + try { + for (int i = 0; i < NUM_MESSAGES; ++i) { + producer.send(session.createTextMessage("TEST")); + TimeUnit.MILLISECONDS.sleep(pause.nextInt(10)); + } + } catch(Exception e) { + LOG.error("Caught an unexpected error: ", e); + } + } + }); + producerThread.start(); + + Thread ackingThread = new Thread(new Runnable() { + + @Override + public void run() { + try { + while (totalConsumed.get() < NUM_MESSAGES) { + Message message = workQueue.take(); + message.acknowledge(); + totalConsumed.incrementAndGet(); + if ((totalConsumed.get() % 100) == 0) { + LOG.info("Consumed " + totalConsumed.get() + " messages so far."); + } + } + } catch(Exception e) { + LOG.error("Caught an unexpected error: ", e); + } + } + }); + ackingThread.start(); + + producerThread.join(); + consumer1Thread.join(); + consumer2Thread.join(); + ackingThread.join(); + + assertEquals(NUM_MESSAGES, totalConsumed.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3779Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3779Test.java new file mode 100644 index 0000000000..5a410e87a4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3779Test.java @@ -0,0 +1,76 @@ +/** + * 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.bugs; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.AutoFailTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.util.LoggingBrokerPlugin; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; + +public class AMQ3779Test extends AutoFailTestSupport { + + private static final Logger logger = Logger.getLogger(AMQ3779Test.class); + private static final String qName = "QNameToFind"; + + public void testLogPerDest() throws Exception { + + final AtomicBoolean ok = new AtomicBoolean(false); + Appender appender = new DefaultTestAppender() { + @Override + public void doAppend(LoggingEvent event) { + if (event.getLoggerName().toString().contains(qName)) { + ok.set(true); + } + } + }; + logger.getRootLogger().addAppender(appender); + + try { + + BrokerService broker = new BrokerService(); + LoggingBrokerPlugin loggingBrokerPlugin = new LoggingBrokerPlugin(); + loggingBrokerPlugin.setPerDestinationLogger(true); + loggingBrokerPlugin.setLogAll(true); + broker.setPlugins(new LoggingBrokerPlugin[]{loggingBrokerPlugin}); + broker.start(); + + + Connection connection = new ActiveMQConnectionFactory(broker.getVmConnectorURI()).createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer messageProducer = session.createProducer(session.createQueue(qName)); + messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + messageProducer.send(session.createTextMessage("Hi")); + connection.close(); + + assertTrue("got expected log message", ok.get()); + } finally { + logger.removeAppender(appender); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3841Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3841Test.java new file mode 100644 index 0000000000..449d5e5539 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3841Test.java @@ -0,0 +1,120 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3841Test { + + static final Logger LOG = LoggerFactory.getLogger(AMQ3841Test.class); + private final static int maxFileLength = 1024*1024*32; + private final static String destinationName = "TEST.QUEUE"; + BrokerService broker; + + @Before + public void setUp() throws Exception { + prepareBrokerWithMultiStore(true); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } + + protected BrokerService createBroker(PersistenceAdapter kaha) throws Exception { + BrokerService broker = new BrokerService(); + broker.setUseJmx(true); + broker.setBrokerName("localhost"); + broker.setPersistenceAdapter(kaha); + return broker; + } + + @Test + public void testRestartAfterQueueDelete() throws Exception { + + // Ensure we have an Admin View. + assertTrue("Broker doesn't have an Admin View.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return (broker.getAdminView()) != null; + } + })); + + + broker.getAdminView().addQueue(destinationName); + + assertNotNull(broker.getDestination(new ActiveMQQueue(destinationName))); + + broker.getAdminView().removeQueue(destinationName); + + broker.stop(); + broker.waitUntilStopped(); + + prepareBrokerWithMultiStore(false); + broker.start(); + + broker.getAdminView().addQueue(destinationName); + assertNotNull(broker.getDestination(new ActiveMQQueue(destinationName))); + + } + + protected KahaDBPersistenceAdapter createStore(boolean delete) throws IOException { + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setJournalMaxFileLength(maxFileLength); + kaha.setCleanupInterval(5000); + if (delete) { + kaha.deleteAllMessages(); + } + return kaha; + } + + public void prepareBrokerWithMultiStore(boolean deleteAllMessages) throws Exception { + + MultiKahaDBPersistenceAdapter multiKahaDBPersistenceAdapter = new MultiKahaDBPersistenceAdapter(); + if (deleteAllMessages) { + multiKahaDBPersistenceAdapter.deleteAllMessages(); + } + ArrayList adapters = new ArrayList(); + + FilteredKahaDBPersistenceAdapter template = new FilteredKahaDBPersistenceAdapter(); + template.setPersistenceAdapter(createStore(deleteAllMessages)); + template.setPerDestination(true); + adapters.add(template); + + multiKahaDBPersistenceAdapter.setFilteredPersistenceAdapters(adapters); + broker = createBroker(multiKahaDBPersistenceAdapter); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3879Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3879Test.java new file mode 100644 index 0000000000..f2bdc480d3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3879Test.java @@ -0,0 +1,112 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3879Test { + + static final Logger LOG = LoggerFactory.getLogger(AMQ3841Test.class); + private BrokerService broker; + + private ActiveMQConnectionFactory factory; + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + + factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setAlwaysSyncSend(true); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.setBrokerName("localhost"); + broker.addConnector("vm://localhost"); + return broker; + } + + @Test + public void testConnectionDletesWrongTempDests() throws Exception { + + final Connection connection1 = factory.createConnection(); + final Connection connection2 = factory.createConnection(); + + Session session1 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Destination tempDestAdvisory = AdvisorySupport.TEMP_QUEUE_ADVISORY_TOPIC; + + MessageConsumer advisoryConsumer = session1.createConsumer(tempDestAdvisory); + connection1.start(); + + Destination tempQueue = session2.createTemporaryQueue(); + MessageProducer tempProducer = session2.createProducer(tempQueue); + + assertNotNull(advisoryConsumer.receive(5000)); + + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + try { + Thread.sleep(20); + connection1.close(); + } catch (Exception e) { + } + } + }); + + t.start(); + + for (int i = 0; i < 256; ++i) { + Message msg = session2.createTextMessage("Temp Data"); + tempProducer.send(msg); + Thread.sleep(2); + } + + t.join(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3903Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3903Test.java new file mode 100644 index 0000000000..c633103176 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3903Test.java @@ -0,0 +1,141 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ResourceAllocationException; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3903Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3903Test.class); + + private static final String bindAddress = "tcp://0.0.0.0:0"; + private BrokerService broker; + private ActiveMQConnectionFactory cf; + + private static final int MESSAGE_COUNT = 100; + + @Before + public void setUp() throws Exception { + broker = this.createBroker(); + String address = broker.getTransportConnectors().get(0).getPublishableConnectString(); + broker.start(); + broker.waitUntilStarted(); + + cf = new ActiveMQConnectionFactory(address); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test + public void testAdvisoryForFastGenericProducer() throws Exception { + doTestAdvisoryForFastProducer(true); + } + + @Test + public void testAdvisoryForFastDedicatedProducer() throws Exception { + doTestAdvisoryForFastProducer(false); + } + + public void doTestAdvisoryForFastProducer(boolean genericProducer) throws Exception { + + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + final TemporaryQueue queue = session.createTemporaryQueue(); + + final Topic advisoryTopic = AdvisorySupport.getFastProducerAdvisoryTopic((ActiveMQDestination) queue); + final Topic advisoryWhenFullTopic = AdvisorySupport.getFullAdvisoryTopic((ActiveMQDestination) queue); + + MessageConsumer advisoryConsumer = session.createConsumer(advisoryTopic); + MessageConsumer advisoryWhenFullConsumer = session.createConsumer(advisoryWhenFullTopic); + + MessageProducer producer = session.createProducer(genericProducer ? null : queue); + + try { + // send lots of messages to the tempQueue + for (int i = 0; i < MESSAGE_COUNT; i++) { + BytesMessage m = session.createBytesMessage(); + m.writeBytes(new byte[1024]); + if (genericProducer) { + producer.send(queue, m, DeliveryMode.PERSISTENT, 4, 0); + } else { + producer.send(m); + } + } + } catch (ResourceAllocationException expectedOnLimitReachedAfterFastAdvisory) {} + + // check one advisory message has produced on the advisoryTopic + Message advCmsg = advisoryConsumer.receive(4000); + assertNotNull(advCmsg); + + advCmsg = advisoryWhenFullConsumer.receive(4000); + assertNotNull(advCmsg); + + connection.close(); + LOG.debug("Connection closed, destinations should now become inactive."); + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.setUseJmx(false); + + PolicyEntry entry = new PolicyEntry(); + entry.setAdvisoryForFastProducers(true); + entry.setAdvisoryWhenFull(true); + entry.setMemoryLimit(10000); + PolicyMap map = new PolicyMap(); + map.setDefaultEntry(entry); + + answer.setDestinationPolicy(map); + answer.addConnector(bindAddress); + + answer.getSystemUsage().setSendFailIfNoSpace(true); + + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3932Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3932Test.java new file mode 100644 index 0000000000..78017a6c58 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3932Test.java @@ -0,0 +1,158 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3932Test { + static final Logger LOG = LoggerFactory.getLogger(AMQ3932Test.class); + private Connection connection; + private BrokerService broker; + + @Before + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + TransportConnector tcpConnector = broker.addConnector("tcp://localhost:0"); + broker.start(); + + ConnectionFactory factory = new ActiveMQConnectionFactory( + "failover:("+ tcpConnector.getPublishableConnectString() +")?jms.prefetchPolicy.queuePrefetch=0"); + connection = factory.createConnection(); + connection.start(); + } + + @After + public void tearDown() throws Exception { + connection.close(); + + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + } + + @Test + public void testPlainReceiveBlocks() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = session.createConsumer(session.createQueue(getClass().getName())); + + broker.stop(); + broker.waitUntilStopped(); + broker = null; + + final CountDownLatch done = new CountDownLatch(1); + final CountDownLatch started = new CountDownLatch(1); + ExecutorService executor = Executors.newSingleThreadExecutor(); + + executor.execute(new Runnable() { + public void run() { + try { + started.countDown(); + LOG.info("Entering into a Sync receive call"); + consumer.receive(); + } catch (JMSException e) { + } + done.countDown(); + } + }); + + assertTrue(started.await(10, TimeUnit.SECONDS)); + assertFalse(done.await(20, TimeUnit.SECONDS)); + } + + @Test + public void testHungReceiveNoWait() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = session.createConsumer(session.createQueue(getClass().getName())); + + broker.stop(); + broker.waitUntilStopped(); + broker = null; + + final CountDownLatch done = new CountDownLatch(1); + final CountDownLatch started = new CountDownLatch(1); + ExecutorService executor = Executors.newSingleThreadExecutor(); + + executor.execute(new Runnable() { + public void run() { + try { + started.countDown(); + LOG.info("Entering into a Sync receiveNoWait call"); + consumer.receiveNoWait(); + } catch (JMSException e) { + } + done.countDown(); + } + }); + + assertTrue(started.await(10, TimeUnit.SECONDS)); + assertTrue(done.await(20, TimeUnit.SECONDS)); + } + + @Test + public void testHungReceiveTimed() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = session.createConsumer(session.createQueue(getClass().getName())); + + broker.stop(); + broker.waitUntilStopped(); + broker = null; + + final CountDownLatch done = new CountDownLatch(1); + final CountDownLatch started = new CountDownLatch(1); + ExecutorService executor = Executors.newSingleThreadExecutor(); + + executor.execute(new Runnable() { + public void run() { + try { + started.countDown(); + LOG.info("Entering into a timed Sync receive call"); + consumer.receive(10); + } catch (JMSException e) { + } + done.countDown(); + } + }); + + assertTrue(started.await(10, TimeUnit.SECONDS)); + assertTrue(done.await(20, TimeUnit.SECONDS)); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3934Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3934Test.java new file mode 100644 index 0000000000..80a2fa3924 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3934Test.java @@ -0,0 +1,105 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class AMQ3934Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3934Test.class); + private static BrokerService brokerService; + private static String TEST_QUEUE = "testQueue"; + private static ActiveMQQueue queue = new ActiveMQQueue(TEST_QUEUE); + private static String BROKER_ADDRESS = "tcp://localhost:0"; + + private ActiveMQConnectionFactory connectionFactory; + private String connectionUri; + private String messageID; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + brokerService.waitUntilStarted(); + + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + sendMessage(); + } + + public void sendMessage() throws Exception { + final Connection conn = connectionFactory.createConnection(); + try { + conn.start(); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Destination queue = session.createQueue(TEST_QUEUE); + final Message toSend = session.createMessage(); + final MessageProducer producer = session.createProducer(queue); + producer.send(queue, toSend); + } finally { + conn.close(); + } + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void getMessage() throws Exception { + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + final CompositeData messages[] = queueView.browse(); + messageID = (String) messages[0].get("JMSMessageID"); + assertNotNull(messageID); + assertNotNull(queueView.getMessage(messageID)); + LOG.debug("Attempting to remove message ID: " + messageID); + queueView.removeMessage(messageID); + assertNull(queueView.getMessage(messageID)); + } + + private QueueViewMBean getProxyToQueueViewMBean() throws MalformedObjectNameException, NullPointerException, + JMSException { + final ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queue.getQueueName()); + final QueueViewMBean proxy = (QueueViewMBean) brokerService.getManagementContext().newProxyInstance( + queueViewMBeanName, QueueViewMBean.class, true); + return proxy; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3961Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3961Test.java new file mode 100644 index 0000000000..8afcaa9719 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3961Test.java @@ -0,0 +1,185 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.jms.ConnectionConsumer; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.ServerSession; +import javax.jms.ServerSessionPool; +import javax.jms.Session; +import javax.jms.TopicConnection; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ3961Test { + + private static BrokerService brokerService; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + + private ActiveMQConnectionFactory connectionFactory; + private String connectionUri; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + brokerService.setDeleteAllMessagesOnStartup(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + brokerService.waitUntilStarted(); + + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + public class TestServerSessionPool implements ServerSessionPool { + + private final TopicConnection connection; + + public TestServerSessionPool(final TopicConnection connection) { + this.connection = connection; + } + + @Override + public ServerSession getServerSession() throws JMSException { + final TopicSession topicSession = connection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); + return new TestServerSession(topicSession); + } + } + + public class TestServerSession implements ServerSession, MessageListener { + + private final TopicSession session; + + public TestServerSession(final TopicSession session) throws JMSException { + this.session = session; + session.setMessageListener(this); + } + + @Override + public Session getSession() throws JMSException { + return session; + } + + @Override + public void start() throws JMSException { + session.run(); + } + + @Override + public void onMessage(final Message message) { + synchronized (processedSessions) { + processedSessions.add(this); + } + } + } + + public static final int MESSAGE_COUNT = 16; + private final List processedSessions = new LinkedList(); + private final List committedSessions = new LinkedList(); + + @Test + public void testPrefetchInDurableSubscription() throws Exception { + final ActiveMQTopic topic = new ActiveMQTopic("TestTopic"); + + final TopicConnection initialSubConnection = connectionFactory.createTopicConnection(); + initialSubConnection.setClientID("TestClient"); + initialSubConnection.start(); + final TopicSession initialSubSession = initialSubConnection.createTopicSession(false, Session.CLIENT_ACKNOWLEDGE); + final TopicSubscriber initialSubscriber = initialSubSession.createDurableSubscriber(topic, "TestSubscriber"); + + initialSubscriber.close(); + initialSubSession.close(); + initialSubConnection.close(); + + final TopicConnection publisherConnection = connectionFactory.createTopicConnection(); + publisherConnection.start(); + final TopicSession publisherSession = publisherConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicPublisher publisher = publisherSession.createPublisher(topic); + for (int i = 1; i <= MESSAGE_COUNT; i++) { + final Message msg = publisherSession.createTextMessage("Message #" + i); + publisher.publish(msg); + } + publisher.close(); + publisherSession.close(); + publisherConnection.close(); + + final TopicConnection connection = connectionFactory.createTopicConnection(); + connection.setClientID("TestClient"); + connection.start(); + final TestServerSessionPool pool = new TestServerSessionPool(connection); + final ConnectionConsumer connectionConsumer = connection.createDurableConnectionConsumer(topic, "TestSubscriber", null, pool, 1); + while (true) { + int lastMsgCount = 0; + int msgCount = 0; + do { + lastMsgCount = msgCount; + Thread.sleep(200L); + synchronized (processedSessions) { + msgCount = processedSessions.size(); + } + } while (lastMsgCount < msgCount); + + if (lastMsgCount == 0) { + break; + } + + final LinkedList collected; + synchronized (processedSessions) { + collected = new LinkedList(processedSessions); + processedSessions.clear(); + } + + final Iterator sessions = collected.iterator(); + while (sessions.hasNext()) { + final TestServerSession session = sessions.next(); + committedSessions.add(session); + session.getSession().commit(); + session.getSession().close(); + } + } + + connectionConsumer.close(); + final TopicSession finalSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + finalSession.unsubscribe("TestSubscriber"); + finalSession.close(); + connection.close(); + assertEquals(MESSAGE_COUNT, committedSessions.size()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3992Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3992Test.java new file mode 100644 index 0000000000..c359c887c0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3992Test.java @@ -0,0 +1,107 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.broker.jmx.DurableSubscriptionViewMBean; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ3992Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3992Test.class); + private static BrokerService brokerService; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + + private String connectionUri; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + brokerService.setDeleteAllMessagesOnStartup(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + brokerService.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testDurableConsumerEnqueueCountWithZeroPrefetch() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionUri); + connectionFactory.getPrefetchPolicy().setAll(0); + + Connection connection = connectionFactory.createConnection(); + connection.setClientID(getClass().getName()); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTopic("DurableTopic"); + + MessageConsumer consumer = session.createDurableSubscriber((Topic) destination, "EnqueueSub"); + + BrokerView view = brokerService.getAdminView(); + view.getDurableTopicSubscribers(); + + ObjectName subName = view.getDurableTopicSubscribers()[0]; + + DurableSubscriptionViewMBean sub = (DurableSubscriptionViewMBean) + brokerService.getManagementContext().newProxyInstance(subName, DurableSubscriptionViewMBean.class, true); + + assertEquals(0, sub.getEnqueueCounter()); + + LOG.info("Enqueue counter for sub before pull requests: " + sub.getEnqueueCounter()); + + // Trigger some pull Timeouts. + consumer.receive(500); + consumer.receive(500); + consumer.receive(500); + consumer.receive(500); + consumer.receive(500); + + // Let them all timeout. + Thread.sleep(600); + + LOG.info("Enqueue counter for sub after pull requests: " + sub.getEnqueueCounter()); + assertEquals(0, sub.getEnqueueCounter()); + + consumer.close(); + session.close(); + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4062Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4062Test.java new file mode 100644 index 0000000000..a567455adf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4062Test.java @@ -0,0 +1,276 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DurableTopicSubscription; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.Subscription; +import org.apache.activemq.broker.region.TopicRegion; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.SubscriptionKey; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ4062Test { + + private BrokerService service; + private PolicyEntry policy; + private ConcurrentHashMap durableSubscriptions; + + private static final int PREFETCH_SIZE_5=5; + private String connectionUri; + + @Before + public void startBroker() throws IOException, Exception { + service=new BrokerService(); + service.setPersistent(true); + service.setDeleteAllMessagesOnStartup(true); + service.setUseJmx(false); + + KahaDBPersistenceAdapter pa=new KahaDBPersistenceAdapter(); + File dataFile=new File("createData"); + pa.setDirectory(dataFile); + pa.setJournalMaxFileLength(1024*1024*32); + + service.setPersistenceAdapter(pa); + + policy = new PolicyEntry(); + policy.setTopic(">"); + policy.setDurableTopicPrefetch(PREFETCH_SIZE_5); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + service.setDestinationPolicy(pMap); + + service.addConnector("tcp://localhost:0"); + + service.start(); + service.waitUntilStarted(); + + connectionUri = service.getTransportConnectors().get(0).getPublishableConnectString(); + } + + public void restartBroker() throws IOException, Exception { + service=new BrokerService(); + service.setPersistent(true); + service.setUseJmx(false); + service.setKeepDurableSubsActive(false); + + KahaDBPersistenceAdapter pa=new KahaDBPersistenceAdapter(); + File dataFile=new File("createData"); + pa.setDirectory(dataFile); + pa.setJournalMaxFileLength(1024*1024*32); + + service.setPersistenceAdapter(pa); + + policy = new PolicyEntry(); + policy.setTopic(">"); + policy.setDurableTopicPrefetch(PREFETCH_SIZE_5); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + service.setDestinationPolicy(pMap); + service.addConnector("tcp://localhost:0"); + service.start(); + service.waitUntilStarted(); + + connectionUri = service.getTransportConnectors().get(0).getPublishableConnectString(); + } + + @After + public void stopBroker() throws Exception { + service.stop(); + service.waitUntilStopped(); + service = null; + } + + @Test + public void testDirableSubPrefetchRecovered() throws Exception{ + + PrefetchConsumer consumer=new PrefetchConsumer(true, connectionUri); + consumer.recieve(); + durableSubscriptions=getDurableSubscriptions(); + ConsumerInfo info=getConsumerInfo(durableSubscriptions); + + //check if the prefetchSize equals to the size we set in the PolicyEntry + assertEquals(PREFETCH_SIZE_5, info.getPrefetchSize()); + + consumer.a.countDown(); + Producer p=new Producer(connectionUri); + p.send(); + p = null; + + service.stop(); + service.waitUntilStopped(); + durableSubscriptions=null; + + consumer = null; + stopBroker(); + + restartBroker(); + + getDurableSubscriptions(); + info=null; + info = getConsumerInfo(durableSubscriptions); + + //check if the prefetchSize equals to 0 after persistent storage recovered + //assertEquals(0, info.getPrefetchSize()); + + consumer=new PrefetchConsumer(false, connectionUri); + consumer.recieve(); + consumer.a.countDown(); + + info=null; + info = getConsumerInfo(durableSubscriptions); + + //check if the prefetchSize is the default size for durable consumer and the PolicyEntry + //we set earlier take no effect + //assertEquals(100, info.getPrefetchSize()); + //info.getPrefetchSize() is 100,it should be 5,because I set the PolicyEntry as follows, + //policy.setDurableTopicPrefetch(PREFETCH_SIZE_5); + assertEquals(5, info.getPrefetchSize()); + } + + @SuppressWarnings("unchecked") + private ConcurrentHashMap getDurableSubscriptions() throws NoSuchFieldException, IllegalAccessException { + if(durableSubscriptions!=null) return durableSubscriptions; + RegionBroker regionBroker=(RegionBroker)service.getRegionBroker(); + TopicRegion region=(TopicRegion)regionBroker.getTopicRegion(); + Field field=TopicRegion.class.getDeclaredField("durableSubscriptions"); + field.setAccessible(true); + durableSubscriptions=(ConcurrentHashMap)field.get(region); + return durableSubscriptions; + } + + private ConsumerInfo getConsumerInfo(ConcurrentHashMap durableSubscriptions) { + ConsumerInfo info=null; + for(Iterator it=durableSubscriptions.values().iterator();it.hasNext();){ + Subscription sub = it.next(); + info=sub.getConsumerInfo(); + if(info.getSubscriptionName().equals(PrefetchConsumer.SUBSCRIPTION_NAME)){ + return info; + } + } + return null; + } + + public class PrefetchConsumer implements MessageListener{ + public static final String SUBSCRIPTION_NAME = "A_NAME_ABC_DEF"; + private final String user = ActiveMQConnection.DEFAULT_USER; + private final String password = ActiveMQConnection.DEFAULT_PASSWORD; + private final String uri; + private boolean transacted; + ActiveMQConnection connection; + Session session; + MessageConsumer consumer; + private boolean needAck=false; + CountDownLatch a=new CountDownLatch(1); + + public PrefetchConsumer(boolean needAck, String uri){ + this.needAck=needAck; + this.uri = uri; + } + + public void recieve() throws Exception{ + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, uri); + connection = (ActiveMQConnection)connectionFactory.createConnection(); + connection.setClientID("3"); + connection.start(); + + session = connection.createSession(transacted, Session.CLIENT_ACKNOWLEDGE); + Destination destination = session.createTopic("topic2"); + consumer = session.createDurableSubscriber((Topic)destination,SUBSCRIPTION_NAME); + consumer.setMessageListener(this); + } + + @Override + public void onMessage(Message message) { + try { + a.await(); + } catch (InterruptedException e1) { + } + if(needAck){ + try { + message.acknowledge(); + consumer.close(); + session.close(); + connection.close(); + } catch (JMSException e) { + } + } + } + } + + public class Producer { + + protected final String user = ActiveMQConnection.DEFAULT_USER; + + private final String password = ActiveMQConnection.DEFAULT_PASSWORD; + private final String uri; + private boolean transacted; + + public Producer(String uri) { + this.uri = uri; + } + + public void send() throws Exception{ + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, uri); + ActiveMQConnection connection = (ActiveMQConnection)connectionFactory.createConnection(); + connection.start(); + + ActiveMQSession session = (ActiveMQSession)connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTopic("topic2"); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + for(int i=0;i<100;i++){ + TextMessage om=session.createTextMessage("hello from producer"); + producer.send(om); + } + producer.close(); + session.close(); + connection.close(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4083Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4083Test.java new file mode 100644 index 0000000000..389f1f613b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4083Test.java @@ -0,0 +1,508 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class AMQ4083Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3992Test.class); + private static BrokerService brokerService; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + private static String TEST_QUEUE = "testQueue"; + private static ActiveMQQueue queue = new ActiveMQQueue(TEST_QUEUE); + + private final int messageCount = 100; + + private String connectionUri; + private String[] data; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + brokerService.setDeleteAllMessagesOnStartup(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + brokerService.waitUntilStarted(); + + data = new String[messageCount]; + + for (int i = 0; i < messageCount; i++) { + data[i] = "Text for message: " + i + " at " + new Date(); + } + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testExpiredMsgsBeforeNonExpired() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.getPrefetchPolicy().setQueuePrefetch(400); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + connection.start(); + + MessageProducer producer = session.createProducer(queue); + MessageConsumer consumer = session.createConsumer(queue); + + // send a batch that expires in a short time. + for (int i = 0; i < 100; i++) { + producer.send(session.createTextMessage(), DeliveryMode.PERSISTENT, 4, 4000); + } + + // and send one that doesn't expire to we can ack it. + producer.send(session.createTextMessage()); + + // wait long enough so the first batch times out. + TimeUnit.SECONDS.sleep(5); + + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + + assertEquals(101, queueView.getInFlightCount()); + + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + try { + message.acknowledge(); + } catch (JMSException e) { + } + } + }); + + TimeUnit.SECONDS.sleep(5); + + assertEquals(0, queueView.getInFlightCount()); + + for (int i = 0; i < 200; i++) { + producer.send(session.createTextMessage()); + } + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + LOG.info("Dequeued Count: {}", queueView.getDequeueCount()); + LOG.info("Dispatch Count: {}", queueView.getDispatchCount()); + LOG.info("Enqueue Count: {}", queueView.getEnqueueCount()); + LOG.info("Expired Count: {}", queueView.getExpiredCount()); + LOG.info("InFlight Count: {}", queueView.getInFlightCount()); + } + + @Test + public void testExpiredMsgsBeforeNonExpiredWithTX() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.getPrefetchPolicy().setQueuePrefetch(400); + + final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + + connection.start(); + + MessageProducer producer = session.createProducer(queue); + MessageConsumer consumer = session.createConsumer(queue); + + // send a batch that expires in a short time. + for (int i = 0; i < 100; i++) { + producer.send(session.createTextMessage(), DeliveryMode.PERSISTENT, 4, 4000); + } + + // and send one that doesn't expire to we can ack it. + producer.send(session.createTextMessage()); + session.commit(); + + // wait long enough so the first batch times out. + TimeUnit.SECONDS.sleep(5); + + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + + assertEquals(101, queueView.getInFlightCount()); + + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + try { + session.commit(); + } catch (JMSException e) { + } + } + }); + + TimeUnit.SECONDS.sleep(5); + + assertEquals(0, queueView.getInFlightCount()); + + for (int i = 0; i < 200; i++) { + producer.send(session.createTextMessage()); + } + session.commit(); + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + LOG.info("Dequeued Count: {}", queueView.getDequeueCount()); + LOG.info("Dispatch Count: {}", queueView.getDispatchCount()); + LOG.info("Enqueue Count: {}", queueView.getEnqueueCount()); + LOG.info("Expired Count: {}", queueView.getExpiredCount()); + LOG.info("InFlight Count: {}", queueView.getInFlightCount()); + } + + @Test + public void testExpiredMsgsInterleavedWithNonExpired() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.getPrefetchPolicy().setQueuePrefetch(400); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + connection.start(); + + MessageProducer producer = session.createProducer(queue); + MessageConsumer consumer = session.createConsumer(queue); + + // send a batch that expires in a short time. + for (int i = 0; i < 200; i++) { + + if ((i % 2) == 0) { + producer.send(session.createTextMessage(), DeliveryMode.PERSISTENT, 4, 4000); + } else { + producer.send(session.createTextMessage()); + } + } + + // wait long enough so the first batch times out. + TimeUnit.SECONDS.sleep(5); + + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + + assertEquals(200, queueView.getInFlightCount()); + + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + try { + LOG.debug("Acking message: {}", message); + message.acknowledge(); + } catch (JMSException e) { + } + } + }); + + TimeUnit.SECONDS.sleep(5); + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + for (int i = 0; i < 200; i++) { + producer.send(session.createTextMessage()); + } + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + LOG.info("Dequeued Count: {}", queueView.getDequeueCount()); + LOG.info("Dispatch Count: {}", queueView.getDispatchCount()); + LOG.info("Enqueue Count: {}", queueView.getEnqueueCount()); + LOG.info("Expired Count: {}", queueView.getExpiredCount()); + LOG.info("InFlight Count: {}", queueView.getInFlightCount()); + } + + @Test + public void testExpiredMsgsInterleavedWithNonExpiredCumulativeAck() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.getPrefetchPolicy().setQueuePrefetch(400); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + connection.start(); + + MessageProducer producer = session.createProducer(queue); + MessageConsumer consumer = session.createConsumer(queue); + + // send a batch that expires in a short time. + for (int i = 0; i < 200; i++) { + + if ((i % 2) == 0) { + producer.send(session.createTextMessage(), DeliveryMode.PERSISTENT, 4, 4000); + } else { + producer.send(session.createTextMessage()); + } + } + + // wait long enough so the first batch times out. + TimeUnit.SECONDS.sleep(5); + + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + + assertEquals(200, queueView.getInFlightCount()); + + final AtomicInteger msgCount = new AtomicInteger(); + + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + try { + if (msgCount.incrementAndGet() == 100) { + LOG.debug("Acking message: {}", message); + message.acknowledge(); + } + } catch (JMSException e) { + } + } + }); + + TimeUnit.SECONDS.sleep(5); + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + // Now we just ack each and see if our counters come out right in the end. + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + try { + LOG.debug("Acking message: {}", message); + message.acknowledge(); + } catch (JMSException e) { + } + } + }); + + for (int i = 0; i < 200; i++) { + producer.send(session.createTextMessage()); + } + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + LOG.info("Dequeued Count: {}", queueView.getDequeueCount()); + LOG.info("Dispatch Count: {}", queueView.getDispatchCount()); + LOG.info("Enqueue Count: {}", queueView.getEnqueueCount()); + LOG.info("Expired Count: {}", queueView.getExpiredCount()); + LOG.info("InFlight Count: {}", queueView.getInFlightCount()); + } + + @Test + public void testExpiredBatchBetweenNonExpiredMessages() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.getPrefetchPolicy().setQueuePrefetch(400); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + connection.start(); + + MessageProducer producer = session.createProducer(queue); + MessageConsumer consumer = session.createConsumer(queue); + + // Send one that doesn't expire so we can ack it. + producer.send(session.createTextMessage()); + + // send a batch that expires in a short time. + for (int i = 0; i < 100; i++) { + producer.send(session.createTextMessage(), DeliveryMode.PERSISTENT, 4, 4000); + } + + // and send one that doesn't expire so we can ack it. + producer.send(session.createTextMessage()); + + // wait long enough so the first batch times out. + TimeUnit.SECONDS.sleep(5); + + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + + assertEquals(102, queueView.getInFlightCount()); + + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + try { + message.acknowledge(); + } catch (JMSException e) { + } + } + }); + + TimeUnit.SECONDS.sleep(5); + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + for (int i = 0; i < 200; i++) { + producer.send(session.createTextMessage()); + } + + assertTrue("Inflight count should reach zero, currently: " + queueView.getInFlightCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return queueView.getInFlightCount() == 0; + } + })); + + LOG.info("Dequeued Count: {}", queueView.getDequeueCount()); + LOG.info("Dispatch Count: {}", queueView.getDispatchCount()); + LOG.info("Enqueue Count: {}", queueView.getEnqueueCount()); + LOG.info("Expired Count: {}", queueView.getExpiredCount()); + LOG.info("InFlight Count: {}", queueView.getInFlightCount()); + } + + @Test + public void testConsumeExpiredQueueAndDlq() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + Connection connection = factory.createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producerNormal = session.createProducer(queue); + MessageProducer producerExpire = session.createProducer(queue); + producerExpire.setTimeToLive(500); + + MessageConsumer dlqConsumer = session.createConsumer(session.createQueue("ActiveMQ.DLQ")); + connection.start(); + + Connection consumerConnection = factory.createConnection(); + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setAll(10); + ((ActiveMQConnection)consumerConnection).setPrefetchPolicy(prefetchPolicy); + Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + String msgBody = new String(new byte[20*1024]); + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(msgBody); + producerExpire.send(queue, message); + } + + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(msgBody); + producerNormal.send(queue, message); + } + + ArrayList messages = new ArrayList(); + Message received; + while ((received = consumer.receive(1000)) != null) { + messages.add(received); + if (messages.size() == 1) { + TimeUnit.SECONDS.sleep(1); + } + received.acknowledge(); + }; + + assertEquals("got messages", messageCount + 1, messages.size()); + + ArrayList dlqMessages = new ArrayList(); + while ((received = dlqConsumer.receive(1000)) != null) { + dlqMessages.add(received); + }; + + assertEquals("got dlq messages", data.length - 1, dlqMessages.size()); + + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + + LOG.info("Dequeued Count: {}", queueView.getDequeueCount()); + LOG.info("Dispatch Count: {}", queueView.getDispatchCount()); + LOG.info("Enqueue Count: {}", queueView.getEnqueueCount()); + LOG.info("Expired Count: {}", queueView.getExpiredCount()); + LOG.info("InFlight Count: {}", queueView.getInFlightCount()); + } + + private QueueViewMBean getProxyToQueueViewMBean() throws Exception { + final ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queue.getQueueName()); + final QueueViewMBean proxy = (QueueViewMBean) brokerService.getManagementContext().newProxyInstance( + queueViewMBeanName, QueueViewMBean.class, true); + return proxy; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4092Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4092Test.java new file mode 100644 index 0000000000..e8c1cf0c47 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4092Test.java @@ -0,0 +1,238 @@ +/** + * 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.bugs; + +import java.util.HashMap; +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 javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4092Test extends TestCase { + + private static final Logger log = LoggerFactory.getLogger(AMQ4092Test.class); + + static final String QUEUE_NAME = "TEST"; + + // increase limits to expedite failure + static final int NUM_TO_SEND_PER_PRODUCER = 1000; // 10000 + static final int NUM_PRODUCERS = 5; // 40 + + static final ActiveMQQueue[] DESTINATIONS = new ActiveMQQueue[]{ + new ActiveMQQueue("A"), + new ActiveMQQueue("B") + // A/B seems to be sufficient for concurrentStoreAndDispatch=true + }; + + static final boolean debug = false; + + private BrokerService brokerService; + + private ActiveMQQueue destination; + private HashMap exceptions = new HashMap(); + private ExceptionListener exceptionListener = new ExceptionListener() { + @Override + public void onException(JMSException exception) { + exception.printStackTrace(); + exceptions.put(Thread.currentThread(), exception); + } + }; + + @Override + protected void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + ((KahaDBPersistenceAdapter)brokerService.getPersistenceAdapter()).setConcurrentStoreAndDispatchQueues(false); + brokerService.addConnector("tcp://localhost:0"); + brokerService.start(); + destination = new ActiveMQQueue(); + destination.setCompositeDestinations(DESTINATIONS); + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + exceptions.put(t, e); + } + }); + } + + @Override + protected void tearDown() throws Exception { + // Stop any running threads. + brokerService.stop(); + } + + + public void testConcurrentGroups() throws Exception { + ExecutorService executorService = Executors.newCachedThreadPool(); + executorService.submit(new TestConsumer()); + for (int i=0; i 0); + + // Consume the message and verify that the test queue is no longer using + // any memory. + MessageConsumer consumer = session.createConsumer(destination); + Message received = consumer.receive(); + Assert.assertNotNull(received); + + // Commit, which ensures message is removed from queue and memory usage + // updated. + session.commit(); + Assert.assertEquals(0, physicalDestination.getMemoryUsage().getUsage()); + + // Resend the message to a different queue and verify that the original + // test queue is still not using any memory. + ActiveMQQueue secondDestination = new ActiveMQQueue(AMQ4116Test.class + ".second"); + MessageProducer secondPproducer = session.createProducer(secondDestination); + + secondPproducer.send(received); + + // Commit, which ensures message is in queue and memory usage updated. + // NOTE: This assertion fails due to bug. + session.commit(); + Assert.assertEquals(0, physicalDestination.getMemoryUsage().getUsage()); + + conn.stop(); + } + + /** + * Create an embedded broker that has both TCP and VM connectors. + */ + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + connectionUri = broker.addConnector(tcpAddr).getPublishableConnectString(); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4126Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4126Test.java new file mode 100644 index 0000000000..4d6d39c47d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4126Test.java @@ -0,0 +1,180 @@ +/** + * 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.bugs; + +import java.net.Socket; +import java.net.URI; + +import javax.management.ObjectName; +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQSslConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.transport.stomp.Stomp; +import org.apache.activemq.transport.stomp.StompConnection; +import org.apache.activemq.transport.stomp.StompFrame; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * + */ +public class AMQ4126Test { + + protected BrokerService broker; + + protected String java_security_auth_login_config = "java.security.auth.login.config"; + protected String xbean = "xbean:"; + protected String confBase = "src/test/resources/org/apache/activemq/bugs/amq4126"; + protected String certBase = "src/test/resources/org/apache/activemq/security"; + protected String JaasStompSSLBroker_xml = "JaasStompSSLBroker.xml"; + protected StompConnection stompConnection = new StompConnection(); + private final static String destinationName = "TEST.QUEUE"; + protected String oldLoginConf = null; + + @Before + public void before() throws Exception { + if (System.getProperty(java_security_auth_login_config) != null) { + oldLoginConf = System.getProperty(java_security_auth_login_config); + } + System.setProperty(java_security_auth_login_config, confBase + "/login.config"); + broker = BrokerFactory.createBroker(xbean + confBase + "/" + JaasStompSSLBroker_xml); + + broker.setDeleteAllMessagesOnStartup(true); + broker.setUseJmx(true); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void after() throws Exception { + broker.stop(); + + if (oldLoginConf != null) { + System.setProperty(java_security_auth_login_config, oldLoginConf); + } + } + + public Socket createSocket(String host, int port) throws Exception { + System.setProperty("javax.net.ssl.trustStore", certBase + "/broker1.ks"); + System.setProperty("javax.net.ssl.trustStorePassword", "password"); + System.setProperty("javax.net.ssl.trustStoreType", "jks"); + System.setProperty("javax.net.ssl.keyStore", certBase + "/client.ks"); + System.setProperty("javax.net.ssl.keyStorePassword", "password"); + System.setProperty("javax.net.ssl.keyStoreType", "jks"); + + SocketFactory factory = SSLSocketFactory.getDefault(); + return factory.createSocket(host, port); + } + + public void stompConnectTo(String connectorName, String extraHeaders) throws Exception { + String host = broker.getConnectorByName(connectorName).getConnectUri().getHost(); + int port = broker.getConnectorByName(connectorName).getConnectUri().getPort(); + stompConnection.open(createSocket(host, port)); + String extra = extraHeaders != null ? extraHeaders : "\n"; + stompConnection.sendFrame("CONNECT\n" + extra + "\n" + Stomp.NULL); + + StompFrame f = stompConnection.receive(); + TestCase.assertEquals(f.getBody(), "CONNECTED", f.getAction()); + stompConnection.close(); + } + + @Test + public void testStompSSLWithUsernameAndPassword() throws Exception { + stompConnectTo("stomp+ssl", "login:system\n" + "passcode:manager\n"); + } + + @Test + public void testStompSSLWithCertificate() throws Exception { + stompConnectTo("stomp+ssl", null); + } + + @Test + public void testStompNIOSSLWithUsernameAndPassword() throws Exception { + stompConnectTo("stomp+nio+ssl", "login:system\n" + "passcode:manager\n"); + } + + @Test + public void testStompNIOSSLWithCertificate() throws Exception { + stompConnectTo("stomp+nio+ssl", null); + } + + public void openwireConnectTo(String connectorName, String username, String password) throws Exception { + URI brokerURI = broker.getConnectorByName(connectorName).getConnectUri(); + String uri = "ssl://" + brokerURI.getHost() + ":" + brokerURI.getPort(); + ActiveMQSslConnectionFactory cf = new ActiveMQSslConnectionFactory(uri); + cf.setTrustStore("org/apache/activemq/security/broker1.ks"); + cf.setTrustStorePassword("password"); + cf.setKeyStore("org/apache/activemq/security/client.ks"); + cf.setKeyStorePassword("password"); + ActiveMQConnection connection = null; + if (username != null || password != null) { + connection = (ActiveMQConnection)cf.createConnection(username, password); + } else { + connection = (ActiveMQConnection)cf.createConnection(); + } + TestCase.assertNotNull(connection); + connection.start(); + connection.stop(); + } + + @Test + public void testOpenwireSSLWithUsernameAndPassword() throws Exception { + openwireConnectTo("openwire+ssl", "system", "manager"); + } + + @Test + public void testOpenwireSSLWithCertificate() throws Exception { + openwireConnectTo("openwire+ssl", null, null); + } + + @Test + public void testOpenwireNIOSSLWithUsernameAndPassword() throws Exception { + openwireConnectTo("openwire+nio+ssl", "system", "mmanager"); + } + + @Test + public void testOpenwireNIOSSLWithCertificate() throws Exception { + openwireConnectTo("openwire+nio+ssl", null, null); + } + + @Test + public void testJmx() throws Exception { + TestCase.assertFalse(findDestination(destinationName)); + broker.getAdminView().addQueue(destinationName); + TestCase.assertTrue(findDestination(destinationName)); + broker.getAdminView().removeQueue(destinationName); + TestCase.assertFalse(findDestination(destinationName)); + } + + private boolean findDestination(String name) throws Exception { + ObjectName[] destinations = broker.getAdminView().getQueues(); + for (ObjectName destination : destinations) { + if (destination.toString().contains(name)) { + return true; + } + } + return false; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4133Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4133Test.java new file mode 100644 index 0000000000..9ca08bb801 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4133Test.java @@ -0,0 +1,107 @@ +/** + * 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.bugs; + +import java.net.Socket; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.transport.stomp.Stomp; +import org.apache.activemq.transport.stomp.StompConnection; +import org.apache.activemq.transport.stomp.StompFrame; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ4133Test { + + protected String java_security_auth_login_config = "java.security.auth.login.config"; + protected String xbean = "xbean:"; + protected String confBase = "src/test/resources/org/apache/activemq/bugs/amq4126"; + protected String certBase = "src/test/resources/org/apache/activemq/security"; + protected String activemqXml = "InconsistentConnectorPropertiesBehaviour.xml"; + protected BrokerService broker; + + protected String oldLoginConf = null; + + @Before + public void before() throws Exception { + if (System.getProperty(java_security_auth_login_config) != null) { + oldLoginConf = System.getProperty(java_security_auth_login_config); + } + System.setProperty(java_security_auth_login_config, confBase + "/" + "login.config"); + broker = BrokerFactory.createBroker(xbean + confBase + "/" + activemqXml); + + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void after() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test + public void stompSSLTransportNeedClientAuthTrue() throws Exception { + stompConnectTo("localhost", broker.getConnectorByName("stomp+ssl").getConnectUri().getPort()); + } + + @Test + public void stompSSLNeedClientAuthTrue() throws Exception { + stompConnectTo("localhost", broker.getConnectorByName("stomp+ssl+special").getConnectUri().getPort()); + } + + @Test + public void stompNIOSSLTransportNeedClientAuthTrue() throws Exception { + stompConnectTo("localhost", broker.getConnectorByName("stomp+nio+ssl").getConnectUri().getPort()); + } + + @Test + public void stompNIOSSLNeedClientAuthTrue() throws Exception { + stompConnectTo("localhost", broker.getConnectorByName("stomp+nio+ssl+special").getConnectUri().getPort()); + } + + public Socket createSocket(String host, int port) throws Exception { + System.setProperty("javax.net.ssl.trustStore", certBase + "/" + "broker1.ks"); + System.setProperty("javax.net.ssl.trustStorePassword", "password"); + System.setProperty("javax.net.ssl.trustStoreType", "jks"); + System.setProperty("javax.net.ssl.keyStore", certBase + "/" + "client.ks"); + System.setProperty("javax.net.ssl.keyStorePassword", "password"); + System.setProperty("javax.net.ssl.keyStoreType", "jks"); + + SocketFactory factory = SSLSocketFactory.getDefault(); + return factory.createSocket(host, port); + } + + public void stompConnectTo(String host, int port) throws Exception { + StompConnection stompConnection = new StompConnection(); + stompConnection.open(createSocket(host, port)); + stompConnection.sendFrame("CONNECT\n" + "\n" + Stomp.NULL); + StompFrame f = stompConnection.receive(); + TestCase.assertEquals(f.getBody(), "CONNECTED", f.getAction()); + stompConnection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4147Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4147Test.java new file mode 100644 index 0000000000..cf7ca45fcf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4147Test.java @@ -0,0 +1,211 @@ +/** + * 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.bugs; + +import java.net.URI; +import java.util.concurrent.Semaphore; + +import javax.jms.Message; +import javax.jms.MessageListener; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.DemandForwardingBridgeSupport; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.Wait; + +/** + * This test demonstrates a bug in {@link DemandForwardingBridgeSupport} when + * bridges are VM-to-VM. Specifically, memory usage from the local broker is + * manipulated by the remote broker. + */ +public class AMQ4147Test extends JmsMultipleBrokersTestSupport { + /** + * This test demonstrates the bug: namely, when a message is bridged over + * the VMTransport, its memory usage continues to refer to the originating + * broker. As a result, memory usage is never accounted for on the remote + * broker, and the local broker's memory usage is only decreased once the + * message is consumed on the remote broker. + */ + public void testVMTransportRemoteMemoryUsage() throws Exception { + BrokerService broker1 = createBroker(new URI( + "broker:(vm://broker1)/broker1?persistent=false")); + + BrokerService broker2 = createBroker(new URI( + "broker:(vm://broker2)/broker2?persistent=false")); + + startAllBrokers(); + + // Forward messages from broker1 to broker2 over the VM transport. + bridgeBrokers("broker1", "broker2").start(); + + // Verify that broker1 and broker2's test queues have no memory usage. + ActiveMQDestination testQueue = createDestination( + AMQ4147Test.class.getSimpleName() + ".queue", false); + final Destination broker1TestQueue = broker1.getDestination(testQueue); + final Destination broker2TestQueue = broker2.getDestination(testQueue); + + assertEquals(0, broker1TestQueue.getMemoryUsage().getUsage()); + assertEquals(0, broker2TestQueue.getMemoryUsage().getUsage()); + + // Produce a message to broker1's test queue and verify that broker1's + // memory usage has increased, but broker2 still has no memory usage. + sendMessages("broker1", testQueue, 1); + assertTrue(broker1TestQueue.getMemoryUsage().getUsage() > 0); + assertEquals(0, broker2TestQueue.getMemoryUsage().getUsage()); + + // Create a consumer on broker2 that is synchronized to allow detection + // of "in flight" messages to the consumer. + MessageIdList broker2Messages = getBrokerMessages("broker2"); + final Semaphore consumerReady = new Semaphore(0); + final Semaphore consumerProceed = new Semaphore(0); + + broker2Messages.setParent(new MessageListener() { + @Override + public void onMessage(Message message) { + consumerReady.release(); + try { + consumerProceed.acquire(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + }); + + createConsumer("broker2", testQueue); + + // Verify that when broker2's consumer receives the message, the memory + // usage has moved broker1 to broker2. The first assertion is expected + // to fail due to the bug; the try/finally ensures the consumer is + // released prior to failure so that the broker can shut down. + consumerReady.acquire(); + + try { + assertTrue("Memory Usage Should be Zero: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker1TestQueue.getMemoryUsage().getUsage() == 0; + } + })); + assertTrue(broker2TestQueue.getMemoryUsage().getUsage() > 0); + } finally { + // Consume the message and verify that there is no more memory + // usage. + consumerProceed.release(); + } + + assertTrue("Memory Usage Should be Zero: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker1TestQueue.getMemoryUsage().getUsage() == 0; + } + })); + assertTrue("Memory Usage Should be Zero: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker2TestQueue.getMemoryUsage().getUsage() == 0; + } + })); + } + + /** + * This test demonstrates that the bug is VMTransport-specific and does not + * occur when bridges occur using other protocols. + */ + public void testTcpTransportRemoteMemoryUsage() throws Exception { + BrokerService broker1 = createBroker(new URI( + "broker:(vm://broker1)/broker1?persistent=false")); + + BrokerService broker2 = createBroker(new URI( + "broker:(tcp://localhost:61616)/broker2?persistent=false")); + + startAllBrokers(); + + // Forward messages from broker1 to broker2 over the TCP transport. + bridgeBrokers("broker1", "broker2").start(); + + // Verify that broker1 and broker2's test queues have no memory usage. + ActiveMQDestination testQueue = createDestination( + AMQ4147Test.class.getSimpleName() + ".queue", false); + final Destination broker1TestQueue = broker1.getDestination(testQueue); + final Destination broker2TestQueue = broker2.getDestination(testQueue); + + assertEquals(0, broker1TestQueue.getMemoryUsage().getUsage()); + assertEquals(0, broker2TestQueue.getMemoryUsage().getUsage()); + + // Produce a message to broker1's test queue and verify that broker1's + // memory usage has increased, but broker2 still has no memory usage. + sendMessages("broker1", testQueue, 1); + assertTrue(broker1TestQueue.getMemoryUsage().getUsage() > 0); + assertEquals(0, broker2TestQueue.getMemoryUsage().getUsage()); + + // Create a consumer on broker2 that is synchronized to allow detection + // of "in flight" messages to the consumer. + MessageIdList broker2Messages = getBrokerMessages("broker2"); + final Semaphore consumerReady = new Semaphore(0); + final Semaphore consumerProceed = new Semaphore(0); + + broker2Messages.setParent(new MessageListener() { + @Override + public void onMessage(Message message) { + consumerReady.release(); + try { + consumerProceed.acquire(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + }); + + createConsumer("broker2", testQueue); + + // Verify that when broker2's consumer receives the message, the memory + // usage has moved broker1 to broker2. + consumerReady.acquire(); + + try { + assertTrue("Memory Usage Should be Zero: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker1TestQueue.getMemoryUsage().getUsage() == 0; + } + })); + assertTrue(broker2TestQueue.getMemoryUsage().getUsage() > 0); + } finally { + // Consume the message and verify that there is no more memory + // usage. + consumerProceed.release(); + } + + // Pause to allow ACK to be processed. + assertTrue("Memory Usage Should be Zero: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker1TestQueue.getMemoryUsage().getUsage() == 0; + } + })); + assertTrue("Memory Usage Should be Zero: ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker2TestQueue.getMemoryUsage().getUsage() == 0; + } + })); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4148Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4148Test.java new file mode 100644 index 0000000000..906131ef18 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4148Test.java @@ -0,0 +1,95 @@ +/** + * 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.bugs; + +import java.net.URI; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.DemandForwardingBridgeSupport; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; +import org.junit.Assert; + +/** + * This test demonstrates a bug in {@link DemandForwardingBridgeSupport} whereby + * a static subscription from broker1 to broker2 is forwarded to broker3 even + * though the network TTL is 1. This results in duplicate subscriptions on + * broker3. + */ +public class AMQ4148Test extends JmsMultipleBrokersTestSupport { + + public void test() throws Exception { + // Create a hub-and-spoke network where each hub-spoke pair share + // messages on a test queue. + BrokerService hub = createBroker(new URI("broker:(vm://hub)/hub?persistent=false")); + + final BrokerService[] spokes = new BrokerService[4]; + for (int i = 0; i < spokes.length; i++) { + spokes[i] = createBroker(new URI("broker:(vm://spoke" + i + ")/spoke" + i + "?persistent=false")); + + } + startAllBrokers(); + + ActiveMQDestination testQueue = createDestination(AMQ4148Test.class.getSimpleName() + ".queue", false); + + NetworkConnector[] ncs = new NetworkConnector[spokes.length]; + for (int i = 0; i < spokes.length; i++) { + NetworkConnector nc = bridgeBrokers("hub", "spoke" + i); + nc.setNetworkTTL(1); + nc.setDuplex(true); + nc.setConduitSubscriptions(false); + nc.setStaticallyIncludedDestinations(Arrays.asList(testQueue)); + nc.start(); + + ncs[i] = nc; + } + + waitForBridgeFormation(); + + // Pause to allow subscriptions to be created. + TimeUnit.SECONDS.sleep(5); + + // Verify that the hub has a subscription from each spoke, but that each + // spoke has a single subscription from the hub (since the network TTL is 1). + final Destination hubTestQueue = hub.getDestination(testQueue); + assertTrue("Expecting {" + spokes.length + "} consumer but was {" + hubTestQueue.getConsumers().size() + "}", + Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return spokes.length == hubTestQueue.getConsumers().size(); + } + }) + ); + + // Now check each spoke has exactly one consumer on the Queue. + for (int i = 0; i < 4; i++) { + Destination spokeTestQueue = spokes[i].getDestination(testQueue); + Assert.assertEquals(1, spokeTestQueue.getConsumers().size()); + } + + for (NetworkConnector nc : ncs) { + nc.stop(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4157Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4157Test.java new file mode 100644 index 0000000000..d29ec08234 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4157Test.java @@ -0,0 +1,175 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Vector; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.BytesMessage; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionControl; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class AMQ4157Test { + static final Logger LOG = LoggerFactory.getLogger(AMQ4157Test.class); + private BrokerService broker; + private ActiveMQConnectionFactory connectionFactory; + private final Destination destination = new ActiveMQQueue("Test"); + private final String payloadString = new String(new byte[8*1024]); + private final boolean useBytesMessage= true; + private final int parallelProducer = 20; + private final int parallelConsumer = 100; + + private final Vector exceptions = new Vector(); + long toSend = 1000; + + @Test + public void testPublishCountsWithRollbackConsumer() throws Exception { + + startBroker(true); + + final AtomicLong sharedCount = new AtomicLong(toSend); + ExecutorService executorService = Executors.newCachedThreadPool(); + + for (int i=0; i< parallelConsumer; i++) { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + consumeOneAndRollback(); + } catch (Exception e) { + exceptions.add(e); + } + } + }); + } + + for (int i=0; i< parallelProducer; i++) { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + publishMessages(sharedCount, 0); + } catch (Exception e) { + exceptions.add(e); + } + } + }); + } + + executorService.shutdown(); + executorService.awaitTermination(30, TimeUnit.MINUTES); + assertTrue("Producers done in time", executorService.isTerminated()); + assertTrue("No exceptions: " + exceptions, exceptions.isEmpty()); + + restartBroker(500); + + LOG.info("Attempting consume of {} messages", toSend); + + consumeMessages(toSend); + } + + private void consumeOneAndRollback() throws Exception { + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(destination); + Message message = null; + while (message == null) { + message = consumer.receive(1000); + } + session.rollback(); + connection.close(); + } + + private void consumeMessages(long count) throws Exception { + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + for (int i=0; i 0) { + Message message = null; + if (useBytesMessage) { + message = session.createBytesMessage(); + ((BytesMessage) message).writeBytes(payloadString.getBytes()); + } else { + message = session.createTextMessage(payloadString); + } + producer.send(message, DeliveryMode.PERSISTENT, 5, expiry); + } + connection.syncSendPacket(new ConnectionControl()); + connection.close(); + } + + public void startBroker(boolean deleteAllMessages) throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + broker.addConnector("tcp://0.0.0.0:0"); + broker.start(); + + String options = "?jms.redeliveryPolicy.maximumRedeliveries=-1&jms.prefetchPolicy.all=1000&jms.watchTopicAdvisories=false&jms.useAsyncSend=true&jms.alwaysSessionAsync=false&jms.dispatchAsync=false&socketBufferSize=131072&ioBufferSize=16384&wireFormat.tightEncodingEnabled=false&wireFormat.cacheSize=8192"; + connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri() + options); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4160Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4160Test.java new file mode 100644 index 0000000000..4867f28c6e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4160Test.java @@ -0,0 +1,393 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.management.ObjectName; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerFilter; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.DiscoveryEvent; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkBridge; +import org.apache.activemq.network.NetworkBridgeListener; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.thread.TaskRunnerFactory; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.discovery.DiscoveryAgent; +import org.apache.activemq.transport.discovery.DiscoveryListener; +import org.apache.activemq.transport.discovery.simple.SimpleDiscoveryAgent; +import org.junit.Assert; + +/** + * This test demonstrates a number of race conditions in + * {@link DiscoveryNetworkConnector} that can result in an active bridge no + * longer being reported as active and vice-versa, an inactive bridge still + * being reported as active. + */ +public class AMQ4160Test extends JmsMultipleBrokersTestSupport { + final long MAX_TEST_TIME = TimeUnit.MINUTES.toMillis(2); + + /** + * Since these tests involve wait conditions, protect against indefinite + * waits (due to unanticipated issues). + */ + public void setUp() throws Exception { + setAutoFail(true); + setMaxTestTime(MAX_TEST_TIME); + super.setUp(); + } + + /** + * This test demonstrates how concurrent attempts to establish a bridge to + * the same remote broker are allowed to occur. Connection uniqueness will + * cause whichever bridge creation attempt is second to fail. However, this + * failure erases the entry in + * {@link DiscoveryNetworkConnector#activeBridges()} that represents the + * successful first bridge creation attempt. + */ + public void testLostActiveBridge() throws Exception { + final long ATTEMPT_TO_CREATE_DELAY = TimeUnit.SECONDS.toMillis(15); + + // Start two brokers with a bridge from broker1 to broker2. + BrokerService broker1 = createBroker(new URI( + "broker:(vm://broker1)/broker1?persistent=false")); + final BrokerService broker2 = createBroker(new URI( + "broker:(vm://broker2)/broker2?persistent=false")); + + // Allow the concurrent local bridge connections to be made even though + // they are duplicated; this prevents both of the bridge attempts from + // failing in the case that the local and remote bridges are established + // out-of-order. + BrokerPlugin ignoreAddConnectionPlugin = new BrokerPlugin() { + @Override + public Broker installPlugin(Broker broker) throws Exception { + return new BrokerFilter(broker) { + @Override + public void addConnection(ConnectionContext context, + ConnectionInfo info) throws Exception { + // ignore + } + }; + } + }; + + broker1.setPlugins(new BrokerPlugin[] { ignoreAddConnectionPlugin }); + + startAllBrokers(); + + // Start a bridge from broker1 to broker2. The discovery agent attempts + // to create the bridge concurrently with two threads, and the + // synchronization in createBridge ensures that pre-patch both threads + // actually attempt to start bridges. Post-patch, only one thread is + // allowed to start the bridge. + final CountDownLatch attemptLatch = new CountDownLatch(2); + final CountDownLatch createLatch = new CountDownLatch(2); + + DiscoveryNetworkConnector nc = new DiscoveryNetworkConnector() { + @Override + public void onServiceAdd(DiscoveryEvent event) { + // Pre-and-post patch, two threads attempt to establish a bridge + // to the same remote broker. + attemptLatch.countDown(); + super.onServiceAdd(event); + } + + @Override + protected NetworkBridge createBridge(Transport localTransport, + Transport remoteTransport, final DiscoveryEvent event) { + // Pre-patch, the two threads are allowed to create the bridge. + // Post-patch, only the first thread is allowed. Wait a + // reasonable delay once both attempts are detected to allow + // the two bridge creations to occur concurrently (pre-patch). + // Post-patch, the wait will timeout and allow the first (and + // only) bridge creation to occur. + try { + attemptLatch.await(); + createLatch.countDown(); + createLatch.await(ATTEMPT_TO_CREATE_DELAY, + TimeUnit.MILLISECONDS); + return super.createBridge(localTransport, remoteTransport, + event); + } catch (InterruptedException e) { + Thread.interrupted(); + return null; + } + } + }; + + nc.setDiscoveryAgent(new DiscoveryAgent() { + TaskRunnerFactory taskRunner = new TaskRunnerFactory(); + DiscoveryListener listener; + + @Override + public void start() throws Exception { + taskRunner.init(); + taskRunner.execute(new Runnable() { + @Override + public void run() { + listener.onServiceAdd(new DiscoveryEvent(broker2 + .getVmConnectorURI().toString())); + } + }); + taskRunner.execute(new Runnable() { + @Override + public void run() { + listener.onServiceAdd(new DiscoveryEvent(broker2 + .getVmConnectorURI().toString())); + } + }); + } + + @Override + public void stop() throws Exception { + taskRunner.shutdown(); + } + + @Override + public void setDiscoveryListener(DiscoveryListener listener) { + this.listener = listener; + } + + @Override + public void registerService(String name) throws IOException { + } + + @Override + public void serviceFailed(DiscoveryEvent event) throws IOException { + listener.onServiceRemove(event); + } + }); + + broker1.addNetworkConnector(nc); + nc.start(); + + // Wait for the bridge to be formed by the first attempt. + waitForBridge(broker1.getBrokerName(), broker2.getBrokerName(), + MAX_TEST_TIME, TimeUnit.MILLISECONDS); + + // Pre-patch, the second bridge creation attempt fails and removes the + // first (successful) bridge creation attempt from the + // list of active bridges. Post-patch, the second bridge creation + // attempt is prevented, so the first bridge creation attempt + // remains "active". This assertion is expected to fail pre-patch and + // pass post-patch. + Assert.assertFalse(nc.activeBridges().isEmpty()); + } + + /** + * This test demonstrates a race condition where a failed bridge can be + * removed from the list of active bridges in + * {@link DiscoveryNetworkConnector} before it has been added. Eventually, + * the failed bridge is added, but never removed, which causes subsequent + * bridge creation attempts to be ignored. The result is a network connector + * that thinks it has an active bridge, when in fact it doesn't. + */ + public void testInactiveBridgStillActive() throws Exception { + // Start two brokers with a bridge from broker1 to broker2. + BrokerService broker1 = createBroker(new URI( + "broker:(vm://broker1)/broker1?persistent=false")); + final BrokerService broker2 = createBroker(new URI( + "broker:(vm://broker2)/broker2?persistent=false")); + + // Force bridge failure by having broker1 disallow connections. + BrokerPlugin disallowAddConnectionPlugin = new BrokerPlugin() { + @Override + public Broker installPlugin(Broker broker) throws Exception { + return new BrokerFilter(broker) { + @Override + public void addConnection(ConnectionContext context, + ConnectionInfo info) throws Exception { + throw new Exception( + "Test exception to force bridge failure"); + } + }; + } + }; + + broker1.setPlugins(new BrokerPlugin[] { disallowAddConnectionPlugin }); + + startAllBrokers(); + + // Start a bridge from broker1 to broker2. The bridge delays returning + // from start until after the bridge failure has been processed; + // this leaves the first bridge creation attempt recorded as active, + // even though it failed. + final SimpleDiscoveryAgent da = new SimpleDiscoveryAgent(); + da.setServices(new URI[] { broker2.getVmConnectorURI() }); + + final CountDownLatch attemptLatch = new CountDownLatch(3); + final CountDownLatch removedLatch = new CountDownLatch(1); + + DiscoveryNetworkConnector nc = new DiscoveryNetworkConnector() { + @Override + public void onServiceAdd(DiscoveryEvent event) { + attemptLatch.countDown(); + super.onServiceAdd(event); + } + + @Override + public void onServiceRemove(DiscoveryEvent event) { + super.onServiceRemove(event); + removedLatch.countDown(); + } + + @Override + protected NetworkBridge createBridge(Transport localTransport, + Transport remoteTransport, final DiscoveryEvent event) { + final NetworkBridge next = super.createBridge(localTransport, + remoteTransport, event); + return new NetworkBridge() { + + @Override + public void start() throws Exception { + next.start(); + // Delay returning until the failed service has been + // removed. + removedLatch.await(); + } + + @Override + public void stop() throws Exception { + next.stop(); + } + + @Override + public void serviceRemoteException(Throwable error) { + next.serviceRemoteException(error); + } + + @Override + public void serviceLocalException(Throwable error) { + next.serviceLocalException(error); + } + + @Override + public void setNetworkBridgeListener( + NetworkBridgeListener listener) { + next.setNetworkBridgeListener(listener); + } + + @Override + public String getRemoteAddress() { + return next.getRemoteAddress(); + } + + @Override + public String getRemoteBrokerName() { + return next.getRemoteBrokerName(); + } + + @Override + public String getRemoteBrokerId() { + return next.getRemoteBrokerId(); + } + + @Override + public String getLocalAddress() { + return next.getLocalAddress(); + } + + @Override + public String getLocalBrokerName() { + return next.getLocalBrokerName(); + } + + @Override + public long getEnqueueCounter() { + return next.getEnqueueCounter(); + } + + @Override + public long getDequeueCounter() { + return next.getDequeueCounter(); + } + + @Override + public void setMbeanObjectName(ObjectName objectName) { + next.setMbeanObjectName(objectName); + } + + @Override + public ObjectName getMbeanObjectName() { + return next.getMbeanObjectName(); + } + + public void resetStats(){ + next.resetStats(); + } + }; + } + }; + nc.setDiscoveryAgent(da); + + broker1.addNetworkConnector(nc); + nc.start(); + + // All bridge attempts should fail, so the attempt latch should get + // triggered. However, because of the race condition, the first attempt + // is considered successful and causes further attempts to stop. + // Therefore, this wait will time out and cause the test to fail. + Assert.assertTrue(attemptLatch.await(30, TimeUnit.SECONDS)); + } + + /** + * This test verifies that when a network connector is restarted, any + * bridges that were active at the time of the stop are allowed to be + * re-established (i.e., the "active events" data structure in + * {@link DiscoveryNetworkConnector} is reset. + */ + public void testAllowAttemptsAfterRestart() throws Exception { + final long STOP_DELAY = TimeUnit.SECONDS.toMillis(10); + + // Start two brokers with a bridge from broker1 to broker2. + BrokerService broker1 = createBroker(new URI( + "broker:(vm://broker1)/broker1?persistent=false")); + final BrokerService broker2 = createBroker(new URI( + "broker:(vm://broker2)/broker2?persistent=false")); + + startAllBrokers(); + + // Start a bridge from broker1 to broker2. + NetworkConnector nc = bridgeBrokers(broker1.getBrokerName(), + broker2.getBrokerName()); + nc.start(); + + waitForBridge(broker1.getBrokerName(), broker2.getBrokerName(), + MAX_TEST_TIME, TimeUnit.MILLISECONDS); + + // Restart the network connector and verify that the bridge is + // re-established. The pause between start/stop is to account for the + // asynchronous closure. + nc.stop(); + Thread.sleep(STOP_DELAY); + nc.start(); + + waitForBridge(broker1.getBrokerName(), broker2.getBrokerName(), + MAX_TEST_TIME, TimeUnit.MILLISECONDS); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4212Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4212Test.java new file mode 100644 index 0000000000..141a8810f0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4212Test.java @@ -0,0 +1,358 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.disk.journal.DataFile; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4212Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4212Test.class); + + private BrokerService service; + private String connectionUri; + private ActiveMQConnectionFactory cf; + + private final int MSG_COUNT = 256; + + @Before + public void setUp() throws IOException, Exception { + createBroker(true, false); + } + + public void createBroker(boolean deleteAllMessages, boolean recover) throws Exception { + service = new BrokerService(); + service.setBrokerName("InactiveSubTest"); + service.setDeleteAllMessagesOnStartup(deleteAllMessages); + service.setAdvisorySupport(false); + service.setPersistent(true); + service.setUseJmx(true); + service.setKeepDurableSubsActive(false); + + KahaDBPersistenceAdapter pa=new KahaDBPersistenceAdapter(); + File dataFile=new File("KahaDB"); + pa.setDirectory(dataFile); + pa.setJournalMaxFileLength(10*1024); + pa.setCheckpointInterval(TimeUnit.SECONDS.toMillis(5)); + pa.setCleanupInterval(TimeUnit.SECONDS.toMillis(5)); + pa.setForceRecoverIndex(recover); + + service.setPersistenceAdapter(pa); + service.start(); + service.waitUntilStarted(); + + connectionUri = "vm://InactiveSubTest?create=false"; + cf = new ActiveMQConnectionFactory(connectionUri); + } + + private void restartBroker() throws Exception { + stopBroker(); + createBroker(false, false); + } + + private void recoverBroker() throws Exception { + stopBroker(); + createBroker(false, true); + } + + @After + public void stopBroker() throws Exception { + if (service != null) { + service.stop(); + service.waitUntilStopped(); + service = null; + } + } + + @Test + public void testDirableSubPrefetchRecovered() throws Exception { + + ActiveMQQueue queue = new ActiveMQQueue("MyQueue"); + ActiveMQTopic topic = new ActiveMQTopic("MyDurableTopic"); + + // Send to a Queue to create some journal files + sendMessages(queue); + + LOG.info("There are currently [{}] journal log files.", getNumberOfJournalFiles()); + + createInactiveDurableSub(topic); + + assertTrue("Should have an inactive durable sub", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + ObjectName[] subs = service.getAdminView().getInactiveDurableTopicSubscribers(); + return subs != null && subs.length == 1 ? true : false; + } + })); + + // Now send some more to the queue to create even more files. + sendMessages(queue); + + LOG.info("There are currently [{}] journal log files.", getNumberOfJournalFiles()); + assertTrue(getNumberOfJournalFiles() > 1); + + LOG.info("Restarting the broker."); + restartBroker(); + LOG.info("Restarted the broker."); + + LOG.info("There are currently [{}] journal log files.", getNumberOfJournalFiles()); + assertTrue(getNumberOfJournalFiles() > 1); + + assertTrue("Should have an inactive durable sub", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + ObjectName[] subs = service.getAdminView().getInactiveDurableTopicSubscribers(); + return subs != null && subs.length == 1 ? true : false; + } + })); + + // Clear out all queue data + service.getAdminView().removeQueue(queue.getQueueName()); + + assertTrue("Less than two journal files expected, was " + getNumberOfJournalFiles(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return getNumberOfJournalFiles() <= 2; + } + }, TimeUnit.MINUTES.toMillis(2))); + + LOG.info("Sending {} Messages to the Topic.", MSG_COUNT); + // Send some messages to the inactive destination + sendMessages(topic); + + LOG.info("Attempt to consume {} messages from the Topic.", MSG_COUNT); + assertEquals(MSG_COUNT, consumeFromInactiveDurableSub(topic)); + + LOG.info("Recovering the broker."); + recoverBroker(); + LOG.info("Recovering the broker."); + + assertTrue("Should have an inactive durable sub", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + ObjectName[] subs = service.getAdminView().getInactiveDurableTopicSubscribers(); + return subs != null && subs.length == 1 ? true : false; + } + })); + } + + @Test + public void testDurableAcksNotDropped() throws Exception { + + ActiveMQQueue queue = new ActiveMQQueue("MyQueue"); + ActiveMQTopic topic = new ActiveMQTopic("MyDurableTopic"); + + // Create durable sub in first data file. + createInactiveDurableSub(topic); + + assertTrue("Should have an inactive durable sub", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + ObjectName[] subs = service.getAdminView().getInactiveDurableTopicSubscribers(); + return subs != null && subs.length == 1 ? true : false; + } + })); + + // Send to a Topic + sendMessages(topic, 1); + + // Send to a Queue to create some journal files + sendMessages(queue); + + LOG.info("Before consume there are currently [{}] journal log files.", getNumberOfJournalFiles()); + + // Consume all the Messages leaving acks behind. + consumeDurableMessages(topic, 1); + + LOG.info("After consume there are currently [{}] journal log files.", getNumberOfJournalFiles()); + + // Now send some more to the queue to create even more files. + sendMessages(queue); + + LOG.info("More Queued. There are currently [{}] journal log files.", getNumberOfJournalFiles()); + assertTrue(getNumberOfJournalFiles() > 1); + + LOG.info("Restarting the broker."); + restartBroker(); + LOG.info("Restarted the broker."); + + LOG.info("There are currently [{}] journal log files.", getNumberOfJournalFiles()); + assertTrue(getNumberOfJournalFiles() > 1); + + assertTrue("Should have an inactive durable sub", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + ObjectName[] subs = service.getAdminView().getInactiveDurableTopicSubscribers(); + return subs != null && subs.length == 1 ? true : false; + } + })); + + // Clear out all queue data + service.getAdminView().removeQueue(queue.getQueueName()); + + assertTrue("Less than three journal file expected, was " + getNumberOfJournalFiles(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return getNumberOfJournalFiles() <= 3; + } + }, TimeUnit.MINUTES.toMillis(3))); + + // See if we receive any message they should all be acked. + tryConsumeExpectNone(topic); + + LOG.info("There are currently [{}] journal log files.", getNumberOfJournalFiles()); + + LOG.info("Recovering the broker."); + recoverBroker(); + LOG.info("Recovering the broker."); + + LOG.info("There are currently [{}] journal log files.", getNumberOfJournalFiles()); + + assertTrue("Should have an inactive durable sub", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + ObjectName[] subs = service.getAdminView().getInactiveDurableTopicSubscribers(); + return subs != null && subs.length == 1 ? true : false; + } + })); + + // See if we receive any message they should all be acked. + tryConsumeExpectNone(topic); + + assertTrue("Less than three journal file expected, was " + getNumberOfJournalFiles(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return getNumberOfJournalFiles() == 1; + } + }, TimeUnit.MINUTES.toMillis(1))); + } + + private int getNumberOfJournalFiles() throws IOException { + Collection files = + ((KahaDBPersistenceAdapter) service.getPersistenceAdapter()).getStore().getJournal().getFileMap().values(); + int reality = 0; + for (DataFile file : files) { + if (file != null) { + reality++; + } + } + + return reality; + } + + private void createInactiveDurableSub(Topic topic) throws Exception { + Connection connection = cf.createConnection(); + connection.setClientID("Inactive"); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "Inactive"); + consumer.close(); + connection.close(); + } + + private void consumeDurableMessages(Topic topic, int count) throws Exception { + Connection connection = cf.createConnection(); + connection.setClientID("Inactive"); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "Inactive"); + connection.start(); + for (int i = 0; i < count; ++i) { + if (consumer.receive(TimeUnit.SECONDS.toMillis(10)) == null) { + fail("should have received a message"); + } + } + consumer.close(); + connection.close(); + } + + private void tryConsumeExpectNone(Topic topic) throws Exception { + Connection connection = cf.createConnection(); + connection.setClientID("Inactive"); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "Inactive"); + connection.start(); + if (consumer.receive(TimeUnit.SECONDS.toMillis(10)) != null) { + fail("Should be no messages for this durable."); + } + consumer.close(); + connection.close(); + } + + private int consumeFromInactiveDurableSub(Topic topic) throws Exception { + Connection connection = cf.createConnection(); + connection.setClientID("Inactive"); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "Inactive"); + + int count = 0; + + while (consumer.receive(10000) != null) { + count++; + } + + consumer.close(); + connection.close(); + + return count; + } + + private void sendMessages(Destination destination) throws Exception { + sendMessages(destination, MSG_COUNT); + } + + private void sendMessages(Destination destination, int count) throws Exception { + Connection connection = cf.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + for (int i = 0; i < count; ++i) { + TextMessage message = session.createTextMessage("Message #" + i + " for destination: " + destination); + producer.send(message); + } + connection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4213Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4213Test.java new file mode 100644 index 0000000000..fddb6b12f0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4213Test.java @@ -0,0 +1,89 @@ +/** + * 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.bugs; + +import static org.junit.Assert.fail; + +import javax.jms.JMSException; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ProducerInfo; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ4213Test { + + private static BrokerService brokerService; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + private static String TEST_QUEUE = "testQueue"; + private static ActiveMQQueue queue = new ActiveMQQueue(TEST_QUEUE); + + private String connectionUri; + + @SuppressWarnings("unchecked") + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + brokerService.setDeleteAllMessagesOnStartup(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + + brokerService.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + + @Override + public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception { + throw new javax.jms.JMSSecurityException(connectionUri); + } + } + }); + + brokerService.start(); + brokerService.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testExceptionOnProducerCreateThrows() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + connection.start(); + + try { + session.createProducer(queue); + fail("Should not be able to create this producer."); + } catch (JMSException ex) { + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4220Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4220Test.java new file mode 100644 index 0000000000..7084bde44c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4220Test.java @@ -0,0 +1,120 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4220Test { + + static final Logger LOG = LoggerFactory.getLogger(AMQ4220Test.class); + private final static int maxFileLength = 1024*1024*32; + private final static String destinationName = "TEST.QUEUE"; + BrokerService broker; + + @Before + public void setUp() throws Exception { + prepareBrokerWithMultiStore(true); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } + + protected BrokerService createBroker(PersistenceAdapter kaha) throws Exception { + BrokerService broker = new BrokerService(); + broker.setUseJmx(true); + broker.setBrokerName("localhost"); + broker.setPersistenceAdapter(kaha); + return broker; + } + + @Test + public void testRestartAfterQueueDelete() throws Exception { + + // Ensure we have an Admin View. + assertTrue("Broker doesn't have an Admin View.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return (broker.getAdminView()) != null; + } + })); + + + LOG.info("Adding initial destination: {}", destinationName); + + broker.getAdminView().addQueue(destinationName); + + assertNotNull(broker.getDestination(new ActiveMQQueue(destinationName))); + + LOG.info("Removing initial destination: {}", destinationName); + + broker.getAdminView().removeQueue(destinationName); + + LOG.info("Adding back destination: {}", destinationName); + + broker.getAdminView().addQueue(destinationName); + + assertNotNull(broker.getDestination(new ActiveMQQueue(destinationName))); + } + + protected KahaDBPersistenceAdapter createStore(boolean delete) throws IOException { + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setJournalMaxFileLength(maxFileLength); + kaha.setCleanupInterval(5000); + if (delete) { + kaha.deleteAllMessages(); + } + return kaha; + } + + public void prepareBrokerWithMultiStore(boolean deleteAllMessages) throws Exception { + + MultiKahaDBPersistenceAdapter multiKahaDBPersistenceAdapter = new MultiKahaDBPersistenceAdapter(); + if (deleteAllMessages) { + multiKahaDBPersistenceAdapter.deleteAllMessages(); + } + ArrayList adapters = new ArrayList(); + + FilteredKahaDBPersistenceAdapter template = new FilteredKahaDBPersistenceAdapter(); + template.setPersistenceAdapter(createStore(deleteAllMessages)); + template.setPerDestination(true); + adapters.add(template); + + multiKahaDBPersistenceAdapter.setFilteredPersistenceAdapters(adapters); + broker = createBroker(multiKahaDBPersistenceAdapter); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4221Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4221Test.java new file mode 100644 index 0000000000..55e8027704 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4221Test.java @@ -0,0 +1,267 @@ +/** + * 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.bugs; + +import java.util.HashSet; +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.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.plist.PListStoreImpl; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.spi.LoggingEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4221Test extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(AMQ4221Test.class); + public int PAYLOAD_SIZE_BYTES = 4 * 1024; + public int NUM_TO_SEND = 60000; + public int NUM_CONCURRENT_PRODUCERS = 20; + public int QUEUE_COUNT = 1; + public int TMP_JOURNAL_MAX_FILE_SIZE = 10 * 1024 * 1024; + + public int DLQ_PURGE_INTERVAL = 30000; + + public int MESSAGE_TIME_TO_LIVE = 20000; + public int EXPIRE_SWEEP_PERIOD = 200; + public int TMP_JOURNAL_GC_PERIOD = 50; + public int RECEIVE_POLL_PERIOD = 4000; + private int RECEIVE_BATCH = 5000; + + final byte[] payload = new byte[PAYLOAD_SIZE_BYTES]; + final AtomicInteger counter = new AtomicInteger(0); + final HashSet exceptions = new HashSet(); + BrokerService brokerService; + private String brokerUrlString; + ExecutorService executorService = Executors.newCachedThreadPool(); + final AtomicBoolean done = new AtomicBoolean(false); + + public static Test suite() { + return suite(AMQ4221Test.class); + } + + @Override + public void setUp() throws Exception { + + LogManager.getRootLogger().addAppender(new DefaultTestAppender() { + + @Override + public void doAppend(LoggingEvent event) { + if (event.getLevel().isGreaterOrEqual(Level.ERROR)) { + System.err.println("exit on error: " + event.getMessage()); + done.set(true); + new Thread() { + public void run() { + System.exit(787); + } + }.start(); + } + } + }); + + done.set(false); + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setDestinations(new ActiveMQDestination[]{new ActiveMQQueue("ActiveMQ.DLQ")}); + + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setPendingQueuePolicy(new FilePendingQueueMessageStoragePolicy()); + defaultPolicy.setExpireMessagesPeriod(EXPIRE_SWEEP_PERIOD); + defaultPolicy.setProducerFlowControl(false); + defaultPolicy.setMemoryLimit(50 * 1024 * 1024); + + brokerService.getSystemUsage().getMemoryUsage().setLimit(50 * 1024 * 1024); + + + PolicyMap destinationPolicyMap = new PolicyMap(); + destinationPolicyMap.setDefaultEntry(defaultPolicy); + brokerService.setDestinationPolicy(destinationPolicyMap); + + + PListStoreImpl tempDataStore = new PListStoreImpl(); + tempDataStore.setDirectory(brokerService.getTmpDataDirectory()); + tempDataStore.setJournalMaxFileLength(TMP_JOURNAL_MAX_FILE_SIZE); + tempDataStore.setCleanupInterval(TMP_JOURNAL_GC_PERIOD); + tempDataStore.setIndexPageSize(200); + tempDataStore.setIndexEnablePageCaching(false); + + brokerService.setTempDataStore(tempDataStore); + brokerService.setAdvisorySupport(false); + TransportConnector tcp = brokerService.addConnector("tcp://localhost:0"); + brokerService.start(); + brokerUrlString = tcp.getPublishableConnectString(); + } + + @Override + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + executorService.shutdownNow(); + } + + public void testProduceConsumeExpireHalf() throws Exception { + + final org.apache.activemq.broker.region.Queue dlq = + (org.apache.activemq.broker.region.Queue) getDestination(brokerService, new ActiveMQQueue("ActiveMQ.DLQ")); + + if (DLQ_PURGE_INTERVAL > 0) { + executorService.execute(new Runnable() { + @Override + public void run() { + while (!done.get()) { + try { + Thread.sleep(DLQ_PURGE_INTERVAL); + LOG.info("Purge DLQ, current size: " + dlq.getDestinationStatistics().getMessages().getCount()); + dlq.purge(); + } catch (InterruptedException allDone) { + } catch (Throwable e) { + e.printStackTrace(); + exceptions.add(e); + } + } + } + }); + + } + + final CountDownLatch latch = new CountDownLatch(QUEUE_COUNT); + for (int i = 0; i < QUEUE_COUNT; i++) { + final int id = i; + executorService.execute(new Runnable() { + @Override + public void run() { + try { + doProduceConsumeExpireHalf(id, latch); + } catch (Throwable e) { + e.printStackTrace(); + exceptions.add(e); + } + } + }); + } + + while (!done.get()) { + done.set(latch.await(5, TimeUnit.SECONDS)); + } + executorService.shutdown(); + executorService.awaitTermination(5, TimeUnit.MINUTES); + + assertTrue("no exceptions:" + exceptions, exceptions.isEmpty()); + + } + + public void doProduceConsumeExpireHalf(int id, CountDownLatch latch) throws Exception { + + final ActiveMQQueue queue = new ActiveMQQueue("Q" + id); + + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUrlString); + ActiveMQPrefetchPolicy prefecthPolicy = new ActiveMQPrefetchPolicy(); + prefecthPolicy.setAll(0); + factory.setPrefetchPolicy(prefecthPolicy); + Connection connection = factory.createConnection(); + connection.start(); + final MessageConsumer consumer = connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(queue, "on = 'true'"); + + executorService.execute(new Runnable() { + @Override + public void run() { + try { + while (!done.get()) { + Thread.sleep(RECEIVE_POLL_PERIOD); + for (int i = 0; i < RECEIVE_BATCH && !done.get(); i++) { + + Message message = consumer.receive(1000); + if (message != null) { + counter.incrementAndGet(); + if (counter.get() > 0 && counter.get() % 500 == 0) { + LOG.info("received: " + counter.get() + ", " + message.getJMSDestination().toString()); + } + } + } + } + } catch (JMSException ignored) { + + } catch (Exception e) { + e.printStackTrace(); + exceptions.add(e); + } + } + }); + + final AtomicInteger accumulator = new AtomicInteger(0); + final CountDownLatch producersDone = new CountDownLatch(NUM_CONCURRENT_PRODUCERS); + + for (int i = 0; i < NUM_CONCURRENT_PRODUCERS; i++) { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + Connection sendConnection = factory.createConnection(); + sendConnection.start(); + Session sendSession = sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = sendSession.createProducer(queue); + producer.setTimeToLive(MESSAGE_TIME_TO_LIVE); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + while (accumulator.incrementAndGet() < NUM_TO_SEND && !done.get()) { + BytesMessage message = sendSession.createBytesMessage(); + message.writeBytes(payload); + message.setStringProperty("on", String.valueOf(accumulator.get() % 2 == 0)); + producer.send(message); + + } + producersDone.countDown(); + } catch (Exception e) { + e.printStackTrace(); + exceptions.add(e); + } + } + }); + } + + producersDone.await(10, TimeUnit.MINUTES); + + final DestinationStatistics view = getDestinationStatistics(brokerService, queue); + LOG.info("total expired so far " + view.getExpired().getCount() + ", " + queue.getQueueName()); + latch.countDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4222Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4222Test.java new file mode 100644 index 0000000000..d5e58355fa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4222Test.java @@ -0,0 +1,188 @@ +/** + * 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.bugs; + +import java.lang.reflect.Field; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.broker.TransportConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.transport.vm.VMTransportFactory; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Christian Posta + */ +public class AMQ4222Test extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4222Test.class); + + protected BrokerService brokerService; + + @Override + protected void setUp() throws Exception { + super.setUp(); + topic = false; + brokerService = createBroker(); + } + + @Override + protected void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = BrokerFactory.createBroker(new URI("broker:()/localhost?persistent=false")); + broker.start(); + broker.waitUntilStarted(); + return broker; + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost"); + } + + public void testTempQueueCleanedUp() throws Exception { + + Destination requestQueue = createDestination(); + + Connection producerConnection = createConnection(); + producerConnection.start(); + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = producerSession.createProducer(requestQueue); + Destination replyTo = producerSession.createTemporaryQueue(); + MessageConsumer producerSessionConsumer = producerSession.createConsumer(replyTo); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + // let's listen to the response on the queue + producerSessionConsumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + if (message instanceof TextMessage) { + LOG.info("You got a message: " + ((TextMessage) message).getText()); + countDownLatch.countDown(); + } + } catch (JMSException e) { + e.printStackTrace(); + } + } + }); + + producer.send(createRequest(producerSession, replyTo)); + + Connection consumerConnection = createConnection(); + consumerConnection.start(); + Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(requestQueue); + final MessageProducer consumerProducer = consumerSession.createProducer(null); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + consumerProducer.send(message.getJMSReplyTo(), message); + } catch (JMSException e) { + LOG.error("error sending a response on the temp queue"); + e.printStackTrace(); + } + } + }); + + countDownLatch.await(2, TimeUnit.SECONDS); + + // producer has not gone away yet... + org.apache.activemq.broker.region.Destination tempDestination = getDestination(brokerService, + (ActiveMQDestination) replyTo); + assertNotNull(tempDestination); + + // clean up + producer.close(); + producerSession.close(); + producerConnection.close(); + + // producer has gone away.. so the temp queue should not exist anymore... let's see.. + // producer has not gone away yet... + tempDestination = getDestination(brokerService, + (ActiveMQDestination) replyTo); + assertNull(tempDestination); + + // now.. the connection on the broker side for the dude producing to the temp dest will + // still have a reference in his producerBrokerExchange.. this will keep the destination + // from being reclaimed by GC if there is never another send that producer makes... + // let's see if that reference is there... + final TransportConnector connector = VMTransportFactory.CONNECTORS.get("localhost"); + assertNotNull(connector); + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return connector.getConnections().size() == 1; + } + })); + TransportConnection transportConnection = connector.getConnections().get(0); + Map exchanges = getProducerExchangeFromConn(transportConnection); + assertEquals(1, exchanges.size()); + ProducerBrokerExchange exchange = exchanges.values().iterator().next(); + + // so this is the reason for the test... we don't want these exchanges to hold a reference + // to a region destination.. after a send is completed, the destination is not used anymore on + // a producer exchange + assertNull(exchange.getRegionDestination()); + assertNull(exchange.getRegion()); + + } + + @SuppressWarnings("unchecked") + private Map getProducerExchangeFromConn(TransportConnection transportConnection) throws NoSuchFieldException, IllegalAccessException { + Field f = TransportConnection.class.getDeclaredField("producerExchanges"); + f.setAccessible(true); + Map producerExchanges = + (Map)f.get(transportConnection); + return producerExchanges; + } + + private Message createRequest(Session session, Destination replyTo) throws JMSException { + Message message = session.createTextMessage("Payload"); + message.setJMSReplyTo(replyTo); + return message; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4323Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4323Test.java new file mode 100644 index 0000000000..8e6a96fffc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4323Test.java @@ -0,0 +1,161 @@ +/** + * 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.bugs; + +import java.io.File; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.ConsumerThread; +import org.apache.activemq.util.ProducerThread; +import org.apache.activemq.util.Wait; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class AMQ4323Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4323Test.class); + + BrokerService broker = null; + File kahaDbDir = null; + private final Destination destination = new ActiveMQQueue("q"); + final String payload = new String(new byte[1024]); + + protected void startBroker(boolean delete) throws Exception { + broker = new BrokerService(); + + //Start with a clean directory + kahaDbDir = new File(broker.getBrokerDataDirectory(), "KahaDB"); + deleteDir(kahaDbDir); + + broker.setSchedulerSupport(false); + broker.setDeleteAllMessagesOnStartup(delete); + broker.setPersistent(true); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:0"); + + PolicyMap map = new PolicyMap(); + PolicyEntry entry = new PolicyEntry(); + entry.setUseCache(false); + map.setDefaultEntry(entry); + broker.setDestinationPolicy(map); + + configurePersistence(broker, delete); + + broker.start(); + LOG.info("Starting broker.."); + } + + protected void configurePersistence(BrokerService brokerService, boolean deleteAllOnStart) throws Exception { + KahaDBPersistenceAdapter adapter = (KahaDBPersistenceAdapter) brokerService.getPersistenceAdapter(); + + // ensure there are a bunch of data files but multiple entries in each + adapter.setJournalMaxFileLength(1024 * 20); + + // speed up the test case, checkpoint an cleanup early and often + adapter.setCheckpointInterval(500); + adapter.setCleanupInterval(500); + + if (!deleteAllOnStart) { + adapter.setForceRecoverIndex(true); + } + + } + + private boolean deleteDir(File dir) { + if (dir.isDirectory()) { + String[] children = dir.list(); + for (int i = 0; i < children.length; i++) { + boolean success = deleteDir(new File(dir, children[i])); + if (!success) { + return false; + } + } + } + + return dir.delete(); + } + + private int getFileCount(File dir){ + if (dir.isDirectory()) { + String[] children = dir.list(); + return children.length; + } + + return 0; + } + + @Test + public void testCleanupOfFiles() throws Exception { + final int messageCount = 500; + startBroker(true); + int fileCount = getFileCount(kahaDbDir); + assertEquals(4, fileCount); + + Connection connection = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getConnectUri()).createConnection(); + connection.start(); + Session producerSess = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session consumerSess = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ProducerThread producer = new ProducerThread(producerSess, destination) { + @Override + protected Message createMessage(int i) throws Exception { + return sess.createTextMessage(payload + "::" + i); + } + }; + producer.setMessageCount(messageCount); + ConsumerThread consumer = new ConsumerThread(consumerSess, destination); + consumer.setBreakOnNull(false); + consumer.setMessageCount(messageCount); + + producer.start(); + producer.join(); + + consumer.start(); + consumer.join(); + + assertEquals("consumer got all produced messages", producer.getMessageCount(), consumer.getReceived()); + + // verify cleanup + assertTrue("gc worked", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + int fileCount = getFileCount(kahaDbDir); + LOG.info("current filecount:" + fileCount); + return 4 == fileCount; + } + })); + + broker.stop(); + broker.waitUntilStopped(); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4356Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4356Test.java new file mode 100644 index 0000000000..aa3ac2c1a4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4356Test.java @@ -0,0 +1,142 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ4356Test { + + private static BrokerService brokerService; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + + private String connectionUri; + private ActiveMQConnectionFactory cf; + private final String CLIENT_ID = "AMQ4356Test"; + private final String SUBSCRIPTION_NAME = "AMQ4356Test"; + + private void createBroker(boolean deleteOnStart) throws Exception { + brokerService = new BrokerService(); + brokerService.setUseJmx(true); + brokerService.setDeleteAllMessagesOnStartup(deleteOnStart); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + brokerService.waitUntilStarted(); + + } + + private void startBroker() throws Exception { + createBroker(true); + } + + private void restartBroker() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + createBroker(false); + } + + @Before + public void setUp() throws Exception { + startBroker(); + cf = new ActiveMQConnectionFactory(connectionUri); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testVirtualTopicUnsubDurable() throws Exception { + Connection connection = cf.createConnection(); + connection.setClientID(CLIENT_ID); + connection.start(); + + // create consumer 'cluster' + ActiveMQQueue queue1 = new ActiveMQQueue(getVirtualTopicConsumerName()); + ActiveMQQueue queue2 = new ActiveMQQueue(getVirtualTopicConsumerName()); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer c1 = session.createConsumer(queue1); + c1.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + } + }); + MessageConsumer c2 = session.createConsumer(queue2); + c2.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + } + }); + + ActiveMQTopic topic = new ActiveMQTopic(getVirtualTopicName()); + MessageConsumer c3 = session.createDurableSubscriber(topic, SUBSCRIPTION_NAME); + + assertEquals(1, brokerService.getAdminView().getDurableTopicSubscribers().length); + assertEquals(0, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length); + + c3.close(); + + // create topic producer + MessageProducer producer = session.createProducer(topic); + assertNotNull(producer); + + int total = 10; + for (int i = 0; i < total; i++) { + producer.send(session.createTextMessage("message: " + i)); + } + + assertEquals(0, brokerService.getAdminView().getDurableTopicSubscribers().length); + assertEquals(1, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length); + + session.unsubscribe(SUBSCRIPTION_NAME); + connection.close(); + + assertEquals(0, brokerService.getAdminView().getDurableTopicSubscribers().length); + assertEquals(0, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length); + + restartBroker(); + + assertEquals(0, brokerService.getAdminView().getDurableTopicSubscribers().length); + assertEquals(0, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length); + } + + protected String getVirtualTopicName() { + return "VirtualTopic.TEST"; + } + + protected String getVirtualTopicConsumerName() { + return "Consumer.A.VirtualTopic.TEST"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4361Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4361Test.java new file mode 100644 index 0000000000..0e1c46570c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4361Test.java @@ -0,0 +1,157 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.VMPendingSubscriberMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4361Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4361Test.class); + + private BrokerService service; + private String brokerUrlString; + + @Before + public void setUp() throws Exception { + service = new BrokerService(); + service.setDeleteAllMessagesOnStartup(true); + service.setUseJmx(false); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setMemoryLimit(1); + policy.setPendingSubscriberPolicy(new VMPendingSubscriberMessageStoragePolicy()); + policy.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + policy.setProducerFlowControl(true); + policyMap.setDefaultEntry(policy); + service.setDestinationPolicy(policyMap); + + service.setAdvisorySupport(false); + brokerUrlString = service.addConnector("tcp://localhost:0").getPublishableConnectString(); + service.start(); + service.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + if (service != null) { + service.stop(); + service.waitUntilStopped(); + } + } + + @Test + public void testCloseWhenHunk() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrlString); + connectionFactory.setProducerWindowSize(1024); + + // TINY QUEUE is flow controlled after 1024 bytes + final ActiveMQDestination destination = + ActiveMQDestination.createDestination("queue://TINY_QUEUE", (byte) 0xff); + + Connection connection = connectionFactory.createConnection(); + connection.start(); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(destination); + producer.setTimeToLive(0); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + final AtomicReference publishException = new AtomicReference(null); + final AtomicReference closeException = new AtomicReference(null); + final AtomicLong lastLoop = new AtomicLong(System.currentTimeMillis() + 100); + + Thread pubThread = new Thread(new Runnable() { + @Override + public void run() { + try { + byte[] data = new byte[1000]; + new Random(0xdeadbeef).nextBytes(data); + for (int i = 0; i < 10000; i++) { + lastLoop.set(System.currentTimeMillis()); + ObjectMessage objMsg = session.createObjectMessage(); + objMsg.setObject(data); + producer.send(destination, objMsg); + } + } catch (Exception e) { + publishException.set(e); + } + } + }, "PublishingThread"); + pubThread.start(); + + // wait for publisher to deadlock + while (System.currentTimeMillis() - lastLoop.get() < 2000) { + Thread.sleep(100); + } + LOG.info("Publisher deadlock detected."); + + Thread closeThread = new Thread(new Runnable() { + @Override + public void run() { + try { + LOG.info("Attempting close.."); + producer.close(); + } catch (Exception e) { + closeException.set(e); + } + } + }, "ClosingThread"); + closeThread.start(); + + try { + closeThread.join(30000); + } catch (InterruptedException ie) { + assertFalse("Closing thread didn't complete in 10 seconds", true); + } + + try { + pubThread.join(30000); + } catch (InterruptedException ie) { + assertFalse("Publishing thread didn't complete in 10 seconds", true); + } + + assertNull(closeException.get()); + assertNotNull(publishException.get()); + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4368Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4368Test.java new file mode 100644 index 0000000000..13e1cfb856 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4368Test.java @@ -0,0 +1,248 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4368Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4368Test.class); + + private BrokerService broker; + private ActiveMQConnectionFactory connectionFactory; + private final Destination destination = new ActiveMQQueue("large_message_queue"); + private String connectionUri; + + @Before + public void setUp() throws Exception { + broker = createBroker(); + connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString(); + broker.start(); + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + + PolicyEntry policy = new PolicyEntry(); + policy.setUseCache(false); + broker.setDestinationPolicy(new PolicyMap()); + broker.getDestinationPolicy().setDefaultEntry(policy); + + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setCheckForCorruptJournalFiles(true); + kahadb.setCleanupInterval(1000); + + kahadb.deleteAllMessages(); + broker.setPersistenceAdapter(kahadb); + broker.getSystemUsage().getMemoryUsage().setLimit(1024*1024*100); + broker.setUseJmx(false); + + return broker; + } + + abstract class Client implements Runnable { + private final String name; + final AtomicBoolean done = new AtomicBoolean(); + CountDownLatch startedLatch; + CountDownLatch doneLatch = new CountDownLatch(1); + Connection connection; + Session session; + final AtomicLong size = new AtomicLong(); + + Client(String name, CountDownLatch startedLatch) { + this.name = name; + this.startedLatch = startedLatch; + } + + public void start() { + LOG.info("Starting: " + name); + new Thread(this, name).start(); + } + + public void stopAsync() { + done.set(true); + } + + public void stop() throws InterruptedException { + stopAsync(); + if (!doneLatch.await(20, TimeUnit.MILLISECONDS)) { + try { + connection.close(); + doneLatch.await(); + } catch (Exception e) { + } + } + } + + @Override + public void run() { + try { + connection = createConnection(); + connection.start(); + try { + session = createSession(); + work(); + } finally { + try { + connection.close(); + } catch (JMSException ignore) { + } + LOG.info("Stopped: " + name); + } + } catch (Exception e) { + e.printStackTrace(); + done.set(true); + } finally { + doneLatch.countDown(); + } + } + + protected Session createSession() throws JMSException { + return connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + protected Connection createConnection() throws JMSException { + return connectionFactory.createConnection(); + } + + abstract protected void work() throws Exception; + } + + class ProducingClient extends Client { + + ProducingClient(String name, CountDownLatch startedLatch) { + super(name, startedLatch); + } + + private String createMessage() { + StringBuffer stringBuffer = new StringBuffer(); + for (long i = 0; i < 1000000; i++) { + stringBuffer.append("1234567890"); + } + return stringBuffer.toString(); + } + + @Override + protected void work() throws Exception { + String data = createMessage(); + MessageProducer producer = session.createProducer(destination); + startedLatch.countDown(); + while (!done.get()) { + producer.send(session.createTextMessage(data)); + long i = size.incrementAndGet(); + if ((i % 1000) == 0) { + LOG.info("produced " + i + "."); + } + } + } + } + + class ConsumingClient extends Client { + public ConsumingClient(String name, CountDownLatch startedLatch) { + super(name, startedLatch); + } + + @Override + protected void work() throws Exception { + MessageConsumer consumer = session.createConsumer(destination); + startedLatch.countDown(); + while (!done.get()) { + Message msg = consumer.receive(100); + if (msg != null) { + size.incrementAndGet(); + } + } + } + } + + @Test + public void testENTMQ220() throws Exception { + LOG.info("Start test."); + CountDownLatch producer1Started = new CountDownLatch(1); + CountDownLatch producer2Started = new CountDownLatch(1); + CountDownLatch listener1Started = new CountDownLatch(1); + + final ProducingClient producer1 = new ProducingClient("1", producer1Started); + final ProducingClient producer2 = new ProducingClient("2", producer2Started); + final ConsumingClient listener1 = new ConsumingClient("subscriber-1", listener1Started); + final AtomicLong lastSize = new AtomicLong(); + + try { + + producer1.start(); + producer2.start(); + listener1.start(); + + producer1Started.await(15, TimeUnit.SECONDS); + producer2Started.await(15, TimeUnit.SECONDS); + listener1Started.await(15, TimeUnit.SECONDS); + + lastSize.set(listener1.size.get()); + for (int i = 0; i < 10; i++) { + Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return listener1.size.get() > lastSize.get(); + } + }); + long size = listener1.size.get(); + LOG.info("Listener 1: consumed: " + (size - lastSize.get())); + assertTrue("No messages received on iteration: " + i, size > lastSize.get()); + lastSize.set(size); + } + } finally { + LOG.info("Stopping clients"); + producer1.stop(); + producer2.stop(); + listener1.stop(); + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4407Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4407Test.java new file mode 100644 index 0000000000..73d6d69f3d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4407Test.java @@ -0,0 +1,177 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4407Test { + + static final Logger LOG = LoggerFactory.getLogger(AMQ4407Test.class); + private final static int maxFileLength = 1024*1024*32; + + private final static String PREFIX_DESTINATION_NAME = "queue"; + + private final static String DESTINATION_NAME = PREFIX_DESTINATION_NAME + ".test"; + private final static String DESTINATION_NAME_2 = PREFIX_DESTINATION_NAME + "2.test"; + private final static String DESTINATION_NAME_3 = PREFIX_DESTINATION_NAME + "3.test"; + + BrokerService broker; + + @Before + public void setUp() throws Exception { + prepareBrokerWithMultiStore(true); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } + + protected BrokerService createBroker(PersistenceAdapter kaha) throws Exception { + BrokerService broker = new BrokerService(); + broker.setUseJmx(true); + broker.setBrokerName("localhost"); + broker.setPersistenceAdapter(kaha); + return broker; + } + + @Test + public void testRestartAfterQueueDelete() throws Exception { + + // Ensure we have an Admin View. + assertTrue("Broker doesn't have an Admin View.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return (broker.getAdminView()) != null; + } + })); + + + LOG.info("Adding destinations: {}, {}, {}", new Object[] {DESTINATION_NAME, DESTINATION_NAME_3, DESTINATION_NAME_3}); + sendMessage(DESTINATION_NAME, "test 1"); + sendMessage(DESTINATION_NAME_2, "test 1"); + sendMessage(DESTINATION_NAME_3, "test 1"); + + assertNotNull(broker.getDestination(new ActiveMQQueue(DESTINATION_NAME))); + assertNotNull(broker.getDestination(new ActiveMQQueue(DESTINATION_NAME_2))); + assertNotNull(broker.getDestination(new ActiveMQQueue(DESTINATION_NAME_3))); + + + LOG.info("Removing destination: {}", DESTINATION_NAME_2); + broker.getAdminView().removeQueue(DESTINATION_NAME_2); + + LOG.info("Recreating destination: {}", DESTINATION_NAME_2); + sendMessage(DESTINATION_NAME_2, "test 1"); + + Destination destination2 = broker.getDestination(new ActiveMQQueue(DESTINATION_NAME_2)); + assertNotNull(destination2); + assertEquals(1, destination2.getMessageStore().getMessageCount()); + } + + protected KahaDBPersistenceAdapter createStore(boolean delete) throws IOException { + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setJournalMaxFileLength(maxFileLength); + kaha.setCleanupInterval(5000); + if (delete) { + kaha.deleteAllMessages(); + } + return kaha; + } + + public void prepareBrokerWithMultiStore(boolean deleteAllMessages) throws Exception { + + MultiKahaDBPersistenceAdapter multiKahaDBPersistenceAdapter = new MultiKahaDBPersistenceAdapter(); + if (deleteAllMessages) { + multiKahaDBPersistenceAdapter.deleteAllMessages(); + } + ArrayList adapters = new ArrayList(); + + adapters.add(createFilteredKahaDBByDestinationPrefix(PREFIX_DESTINATION_NAME, deleteAllMessages)); + adapters.add(createFilteredKahaDBByDestinationPrefix(PREFIX_DESTINATION_NAME + "2", deleteAllMessages)); + adapters.add(createFilteredKahaDBByDestinationPrefix(null, deleteAllMessages)); + + multiKahaDBPersistenceAdapter.setFilteredPersistenceAdapters(adapters); + broker = createBroker(multiKahaDBPersistenceAdapter); + } + + /** + * Create filtered KahaDB adapter by destination prefix. + * + * @param destinationPrefix + * @param deleteAllMessages + * @return + * @throws IOException + */ + private FilteredKahaDBPersistenceAdapter createFilteredKahaDBByDestinationPrefix(String destinationPrefix, boolean deleteAllMessages) + throws IOException { + FilteredKahaDBPersistenceAdapter template = new FilteredKahaDBPersistenceAdapter(); + template.setPersistenceAdapter(createStore(deleteAllMessages)); + if (destinationPrefix != null) { + template.setQueue(destinationPrefix + ".>"); + } + return template; + } + + + /** + * Send message to particular destination. + * + * @param destinationName + * @param message + * @throws JMSException + */ + private void sendMessage(String destinationName, String message) throws JMSException { + ActiveMQConnectionFactory f = new ActiveMQConnectionFactory("vm://localhost"); + f.setAlwaysSyncSend(true); + Connection c = f.createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = s.createProducer(new ActiveMQQueue(destinationName)); + producer.send(s.createTextMessage(message)); + producer.close(); + s.close(); + c.stop(); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4413Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4413Test.java new file mode 100644 index 0000000000..ff973e916a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4413Test.java @@ -0,0 +1,240 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + */ +public class AMQ4413Test { + + static final Logger LOG = LoggerFactory.getLogger(AMQ4413Test.class); + + final String brokerUrl = "tcp://localhost:0"; + private String connectionUri; + final int numMsgsTriggeringReconnection = 2; + final int numMsgs = 30; + final int numTests = 75; + final ExecutorService threadPool = Executors.newCachedThreadPool(); + + @Test + public void testDurableSubMessageLoss() throws Exception{ + // start embedded broker + BrokerService brokerService = new BrokerService(); + connectionUri = brokerService.addConnector(brokerUrl).getPublishableConnectString(); + brokerService.setPersistent(false); + brokerService.setUseJmx(false); + brokerService.setKeepDurableSubsActive(true); + brokerService.setAdvisorySupport(false); + brokerService.start(); + LOG.info("##### broker started"); + + // repeat test 50 times + try { + for (int i = 0; i < numTests; ++i) { + LOG.info("##### test " + i + " started"); + test(); + } + + LOG.info("##### tests are done"); + } catch (Exception e) { + e.printStackTrace(); + LOG.info("##### tests failed!"); + } finally { + threadPool.shutdown(); + brokerService.stop(); + LOG.info("##### broker stopped"); + } + } + + private void test() throws Exception { + + final String topicName = "topic-" + UUID.randomUUID(); + final String clientId = "client-" + UUID.randomUUID(); + final String subName = "sub-" + UUID.randomUUID(); + + // create (and only create) subscription first + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + factory.setWatchTopicAdvisories(false); + Connection connection = factory.createConnection(); + connection.setClientID(clientId); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic(topicName); + TopicSubscriber durableSubscriptionCreator = session.createDurableSubscriber(topic, subName); + + connection.stop(); + durableSubscriptionCreator.close(); + session.close(); + connection.close(); + + // publisher task + Callable publisher = new Callable() { + @Override + public Boolean call() throws Exception { + Connection connection = null; + + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + factory.setWatchTopicAdvisories(false); + connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic(topicName); + + MessageProducer producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.setPriority(Message.DEFAULT_PRIORITY); + producer.setTimeToLive(Message.DEFAULT_TIME_TO_LIVE); + + for (int seq = 1; seq <= numMsgs; ++seq) { + TextMessage msg = session.createTextMessage(String.valueOf(seq)); + producer.send(msg); + LOG.info("pub sent msg: " + seq); + Thread.sleep(1L); + } + + LOG.info("pub is done"); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + return Boolean.TRUE; + } + }; + + // subscriber task + Callable durableSubscriber = new Callable() { + ActiveMQConnectionFactory factory; + Connection connection; + Session session; + Topic topic; + TopicSubscriber consumer; + + @Override + public Boolean call() throws Exception { + factory = new ActiveMQConnectionFactory(connectionUri); + factory.setWatchTopicAdvisories(false); + + try { + connect(); + + for (int seqExpected = 1; seqExpected <= numMsgs; ++seqExpected) { + TextMessage msg = (TextMessage) consumer.receive(3000L); + if (msg == null) { + LOG.info("expected: " + seqExpected + ", actual: timed out", msg); + return Boolean.FALSE; + } + + int seq = Integer.parseInt(msg.getText()); + + LOG.info("sub received msg: " + seq); + + if (seqExpected != seq) { + LOG.info("expected: " + seqExpected + ", actual: " + seq); + return Boolean.FALSE; + } + + if (seq % numMsgsTriggeringReconnection == 0) { + close(false); + connect(); + + LOG.info("sub reconnected"); + } + } + + LOG.info("sub is done"); + } finally { + try { + close(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + + return Boolean.TRUE; + } + + void connect() throws Exception { + connection = factory.createConnection(); + connection.setClientID(clientId); + connection.start(); + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = session.createTopic(topicName); + consumer = session.createDurableSubscriber(topic, subName); + } + + void close(boolean unsubscribe) throws Exception { + if (connection != null) { + connection.stop(); + } + + if (consumer != null) { + consumer.close(); + } + + if (session != null) { + if (unsubscribe) { + session.unsubscribe(subName); + } + session.close(); + } + + if (connection != null) { + connection.close(); + } + } + }; + + ArrayList> results = new ArrayList>(); + results.add(threadPool.submit(publisher)); + results.add(threadPool.submit(durableSubscriber)); + + for (Future result : results) { + assertTrue(result.get()); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4469Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4469Test.java new file mode 100644 index 0000000000..2f7ae69f18 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4469Test.java @@ -0,0 +1,114 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.transport.tcp.TcpTransportServer; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.jms.support.JmsUtils; + +public class AMQ4469Test { + + private static final int maxConnections = 100; + + private final ExecutorService executor = Executors.newCachedThreadPool(); + private String connectionUri; + private BrokerService service; + private TransportConnector connector; + + @Before + public void setUp() throws Exception { + service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + connector = service.addConnector("tcp://0.0.0.0:0?maximumConnections="+maxConnections); + connectionUri = connector.getPublishableConnectString(); + service.start(); + service.waitUntilStarted(); + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(connectionUri); + } + + @Test + public void testMaxConnectionControl() throws Exception { + final ConnectionFactory cf = createConnectionFactory(); + final CountDownLatch startupLatch = new CountDownLatch(1); + for(int i = 0; i < maxConnections + 20; i++) { + executor.submit(new Runnable() { + @Override + public void run() { + Connection conn = null; + try { + startupLatch.await(); + conn = cf.createConnection(); + conn.start(); + } catch (Exception e) { + e.printStackTrace(); + JmsUtils.closeConnection(conn); + } + } + }); + } + + TcpTransportServer transportServer = (TcpTransportServer)connector.getServer(); + // ensure the max connections is in effect + assertEquals(maxConnections, transportServer.getMaximumConnections()); + // No connections at first + assertEquals(0, connector.getConnections().size()); + // Release the latch to set up connections in parallel + startupLatch.countDown(); + TimeUnit.SECONDS.sleep(5); + + final TransportConnector connector = this.connector; + + // Expect the max connections is created + assertTrue("Expected: " + maxConnections + " found: " + connector.getConnections().size(), + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return connector.getConnections().size() == maxConnections; + } + }) + ); + } + + @After + public void tearDown() throws Exception { + executor.shutdown(); + + service.stop(); + service.waitUntilStopped(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4472Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4472Test.java new file mode 100644 index 0000000000..42c391c85d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4472Test.java @@ -0,0 +1,91 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class AMQ4472Test { + private static final Logger LOG = LoggerFactory.getLogger(AMQ4472Test.class); + + @Test + public void testLostMessage() { + Connection connection = null; + try { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.useJmx=false"); + connection = connectionFactory.createConnection(); + connection.start(); + + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination test_data_destination = session.createQueue("test"+System.currentTimeMillis()); + + MessageConsumer consumer = session.createConsumer(test_data_destination); + LOG.info("Consumer 1 connected"); + + MessageProducer producer = session.createProducer(test_data_destination); + producer.send(session.createTextMessage("Message 1")); + + // committing the session prior to the close + session.commit(); + + // starting a new transaction + producer.send(session.createTextMessage("Message 2")); + + // in a new transaction, with prefetch>0, the message + // 1 will be pending till second commit + LOG.info("Closing consumer 1..."); + consumer.close(); + + // create a consumer + consumer = session.createConsumer(test_data_destination); + LOG.info("Consumer 2 connected"); + + // retrieve message previously committed to tmp queue + Message message = consumer.receive(10000); + if (message != null) { + LOG.info("Got message 1:", message); + assertEquals("expected message", "Message 1", ((TextMessage) message).getText()); + session.commit(); + } else { + LOG.error("Expected message but it never arrived"); + } + assertNotNull(message); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + connection.close(); + } catch (JMSException e) { + } + } + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4475Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4475Test.java new file mode 100644 index 0000000000..3d11cef335 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4475Test.java @@ -0,0 +1,344 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertFalse; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.IndividualDeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.util.TimeStampingBrokerPlugin; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ4475Test { + + private final Log LOG = LogFactory.getLog(AMQ4475Test.class); + + private final int NUM_MSGS = 1000; + private final int MAX_THREADS = 20; + + private BrokerService broker; + private String connectionUri; + + private final ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS); + private final ActiveMQQueue original = new ActiveMQQueue("jms/AQueue"); + private final ActiveMQQueue rerouted = new ActiveMQQueue("jms/AQueue_proxy"); + + @Before + public void setUp() throws Exception { + TimeStampingBrokerPlugin tsbp = new TimeStampingBrokerPlugin(); + tsbp.setZeroExpirationOverride(432000000); + tsbp.setTtlCeiling(432000000); + tsbp.setFutureOnly(true); + + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.setPlugins(new BrokerPlugin[] {tsbp}); + connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString(); + + // Configure Dead Letter Strategy + DeadLetterStrategy strategy = new IndividualDeadLetterStrategy(); + strategy.setProcessExpired(true); + ((IndividualDeadLetterStrategy)strategy).setUseQueueForQueueMessages(true); + ((IndividualDeadLetterStrategy)strategy).setQueuePrefix("DLQ."); + strategy.setProcessNonPersistent(true); + + // Add policy and individual DLQ strategy + PolicyEntry policy = new PolicyEntry(); + policy.setTimeBeforeDispatchStarts(3000); + policy.setDeadLetterStrategy(strategy); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void after() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test + public void testIndividualDeadLetterAndTimeStampPlugin() { + LOG.info("Starting test .."); + + long startTime = System.nanoTime(); + + // Produce to network + List> tasks = new ArrayList>(); + + for (int index = 0; index < 1; index++) { + ProducerTask p = new ProducerTask(connectionUri, original, NUM_MSGS); + Future future = executor.submit(p, p); + tasks.add(future); + } + + ForwardingConsumerThread f1 = new ForwardingConsumerThread(original, rerouted, NUM_MSGS); + f1.start(); + ConsumerThread c1 = new ConsumerThread(connectionUri, rerouted, NUM_MSGS); + c1.start(); + + LOG.info("Waiting on consumers and producers to exit"); + + try { + for (Future future : tasks) { + ProducerTask e = future.get(); + LOG.info("[Completed] " + e.dest.getPhysicalName()); + } + executor.shutdown(); + LOG.info("Producing threads complete, waiting on ACKs"); + f1.join(TimeUnit.MINUTES.toMillis(2)); + c1.join(TimeUnit.MINUTES.toMillis(2)); + } catch (ExecutionException e) { + LOG.warn("Caught unexpected exception: {}", e); + throw new RuntimeException(e); + } catch (InterruptedException ie) { + LOG.warn("Caught unexpected exception: {}", ie); + throw new RuntimeException(ie); + } + + assertFalse(f1.isFailed()); + assertFalse(c1.isFailed()); + + long estimatedTime = System.nanoTime() - startTime; + + LOG.info("Testcase duration (seconds): " + estimatedTime / 1000000000.0); + LOG.info("Consumers and producers exited, all msgs received as expected"); + } + + public class ProducerTask implements Runnable { + private final String uri; + private final ActiveMQQueue dest; + private final int count; + + public ProducerTask(String uri, ActiveMQQueue dest, int count) { + this.uri = uri; + this.dest = dest; + this.count = count; + } + + @Override + public void run() { + + Connection connection = null; + try { + String destName = ""; + + try { + destName = dest.getQueueName(); + } catch (JMSException e) { + LOG.warn("Caught unexpected exception: {}", e); + } + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(uri); + + connection = connectionFactory.createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(dest); + connection.start(); + + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + String msg = "Test Message"; + + for (int i = 0; i < count; i++) { + producer.send(session.createTextMessage(msg + dest.getQueueName() + " " + i)); + } + + LOG.info("[" + destName + "] Sent " + count + " msgs"); + } catch (Exception e) { + LOG.warn("Caught unexpected exception: {}", e); + } finally { + try { + connection.close(); + } catch (Throwable e) { + LOG.warn("Caught unexpected exception: {}", e); + } + } + } + } + + public class ForwardingConsumerThread extends Thread { + + private final ActiveMQQueue original; + private final ActiveMQQueue forward; + private int blockSize = 0; + private final int PARALLEL = 1; + private boolean failed; + + public ForwardingConsumerThread(ActiveMQQueue original, ActiveMQQueue forward, int total) { + this.original = original; + this.forward = forward; + this.blockSize = total / PARALLEL; + } + + public boolean isFailed() { + return failed; + } + + @Override + public void run() { + Connection connection = null; + try { + + for (int index = 0; index < PARALLEL; index++) { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + + connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(original); + MessageProducer producer = session.createProducer(forward); + connection.start(); + int count = 0; + + while (count < blockSize) { + + Message msg1 = consumer.receive(10000); + if (msg1 != null) { + if (msg1 instanceof ActiveMQTextMessage) { + if (count % 100 == 0) { + LOG.info("Consuming -> " + ((ActiveMQTextMessage) msg1).getDestination() + " count=" + count); + } + + producer.send(msg1); + + count++; + } else { + LOG.info("Skipping unknown msg type " + msg1); + } + } else { + break; + } + } + + LOG.info("[" + original.getQueueName() + "] completed segment (" + index + " of " + blockSize + ")"); + connection.close(); + } + } catch (Exception e) { + LOG.warn("Caught unexpected exception: {}", e); + } finally { + LOG.debug(getName() + ": is stopping"); + try { + connection.close(); + } catch (Throwable e) { + } + } + } + } + + public class ConsumerThread extends Thread { + + private final String uri; + private final ActiveMQQueue dest; + private int blockSize = 0; + private final int PARALLEL = 1; + private boolean failed; + + public ConsumerThread(String uri, ActiveMQQueue dest, int total) { + this.uri = uri; + this.dest = dest; + this.blockSize = total / PARALLEL; + } + + public boolean isFailed() { + return failed; + } + + @Override + public void run() { + Connection connection = null; + try { + + for (int index = 0; index < PARALLEL; index++) { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(uri); + + connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(dest); + connection.start(); + int count = 0; + + while (count < blockSize) { + + Object msg1 = consumer.receive(10000); + if (msg1 != null) { + if (msg1 instanceof ActiveMQTextMessage) { + if (count % 100 == 0) { + LOG.info("Consuming -> " + ((ActiveMQTextMessage) msg1).getDestination() + " count=" + count); + } + + count++; + } else { + LOG.info("Skipping unknown msg type " + msg1); + } + } else { + failed = true; + break; + } + } + + LOG.info("[" + dest.getQueueName() + "] completed segment (" + index + " of " + blockSize + ")"); + connection.close(); + } + } catch (Exception e) { + LOG.warn("Caught unexpected exception: {}", e); + } finally { + LOG.debug(getName() + ": is stopping"); + try { + connection.close(); + } catch (Throwable e) { + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485LowLimitLevelDBTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485LowLimitLevelDBTest.java new file mode 100644 index 0000000000..5a485404c8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485LowLimitLevelDBTest.java @@ -0,0 +1,38 @@ +/** + * 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.bugs; + +import java.io.File; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; + +public class AMQ4485LowLimitLevelDBTest extends AMQ4485LowLimitTest { + + public AMQ4485LowLimitLevelDBTest() { + super(); + numBrokers = 2; + } + + protected BrokerService createBroker(int brokerid, boolean addToNetwork) throws Exception { + BrokerService broker = super.createBroker(brokerid, addToNetwork); + + LevelDBStore levelDBStore = new LevelDBStore(); + levelDBStore.setDirectory(new File(broker.getBrokerDataDirectory(),"levelDB")); + broker.setPersistenceAdapter(levelDBStore); + return broker; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485LowLimitTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485LowLimitTest.java new file mode 100644 index 0000000000..21c389f390 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485LowLimitTest.java @@ -0,0 +1,466 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.QueueConnection; +import javax.jms.QueueReceiver; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.ObjectName; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.TimeUtils; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4485LowLimitTest extends JmsMultipleBrokersTestSupport { + static final String payload = new String(new byte[10 * 1024]); + private static final Logger LOG = LoggerFactory.getLogger(AMQ4485LowLimitTest.class); + final int portBase = 61600; + int numBrokers = 8; + final int numProducers = 30; + final int numMessages = 1000; + final int consumerSleepTime = 40; + StringBuilder brokersUrl = new StringBuilder(); + HashMap accumulators = new HashMap(); + private ArrayList exceptions = new ArrayList(); + + protected void buildUrlList() throws Exception { + for (int i = 0; i < numBrokers; i++) { + brokersUrl.append("tcp://localhost:" + (portBase + i)); + if (i != numBrokers - 1) { + brokersUrl.append(','); + } + } + } + + protected BrokerService createBroker(int brokerid) throws Exception { + return createBroker(brokerid, true); + } + + protected BrokerService createBroker(int brokerid, boolean addToNetwork) throws Exception { + + BrokerService broker = new BrokerService(); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(true); + broker.getManagementContext().setCreateConnector(false); + + + broker.setUseJmx(true); + broker.setBrokerName("B" + brokerid); + broker.addConnector(new URI("tcp://localhost:" + (portBase + brokerid))); + + if (addToNetwork) { + addNetworkConnector(broker); + } + broker.setSchedulePeriodForDestinationPurge(0); + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024l); + + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setExpireMessagesPeriod(0); + policyEntry.setQueuePrefetch(1000); + policyEntry.setMemoryLimit(2 * 1024 * 1024l); + policyEntry.setProducerFlowControl(false); + policyEntry.setEnableAudit(true); + policyEntry.setUseCache(true); + policyMap.put(new ActiveMQQueue("GW.>"), policyEntry); + + PolicyEntry inPolicyEntry = new PolicyEntry(); + inPolicyEntry.setExpireMessagesPeriod(0); + inPolicyEntry.setQueuePrefetch(1000); + inPolicyEntry.setMemoryLimit(5 * 1024 * 1024l); + inPolicyEntry.setProducerFlowControl(true); + inPolicyEntry.setEnableAudit(true); + inPolicyEntry.setUseCache(true); + policyMap.put(new ActiveMQQueue("IN"), inPolicyEntry); + + broker.setDestinationPolicy(policyMap); + + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + kahaDBPersistenceAdapter.setConcurrentStoreAndDispatchQueues(true); + + brokers.put(broker.getBrokerName(), new BrokerItem(broker)); + return broker; + } + + private void addNetworkConnector(BrokerService broker) throws Exception { + StringBuilder networkConnectorUrl = new StringBuilder("static:(").append(brokersUrl.toString()); + networkConnectorUrl.append(')'); + + for (int i = 0; i < 2; i++) { + NetworkConnector nc = new DiscoveryNetworkConnector(new URI(networkConnectorUrl.toString())); + nc.setName("Bridge-" + i); + nc.setNetworkTTL(1); + nc.setDecreaseNetworkConsumerPriority(true); + nc.setDynamicOnly(true); + nc.setPrefetchSize(100); + nc.setDynamicallyIncludedDestinations( + Arrays.asList(new ActiveMQDestination[]{new ActiveMQQueue("GW.*")})); + broker.addNetworkConnector(nc); + } + } + + // used to explore contention with concurrentStoreandDispatch - sync commit and task queue reversing + // order of cursor add and sequence assignment + public void x_testInterleavedSend() throws Exception { + + BrokerService b = createBroker(0, false); + b.start(); + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:" + (portBase + 0)); + connectionFactory.setWatchTopicAdvisories(false); + + QueueConnection c1 = connectionFactory.createQueueConnection(); + QueueConnection c2 = connectionFactory.createQueueConnection(); + QueueConnection c3 = connectionFactory.createQueueConnection(); + + c1.start(); + c2.start(); + c3.start(); + + ActiveMQQueue dest = new ActiveMQQueue("IN"); + final Session s1 = c1.createQueueSession(true, Session.SESSION_TRANSACTED); + final TextMessage txMessage = s1.createTextMessage("TX"); + final TextMessage noTxMessage = s1.createTextMessage("NO_TX"); + + final MessageProducer txProducer = s1.createProducer(dest); + final MessageProducer nonTxProducer = c2.createQueueSession(false, Session.AUTO_ACKNOWLEDGE).createProducer(dest); + + txProducer.send(txMessage); + + ExecutorService executorService = Executors.newFixedThreadPool(2); + executorService.execute(new Runnable() { + @Override + public void run() { + try { + s1.commit(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + }); + + executorService.execute(new Runnable() { + @Override + public void run() { + try { + nonTxProducer.send(noTxMessage); + } catch (JMSException e) { + e.printStackTrace(); + } + } + }); + + executorService.shutdown(); + executorService.awaitTermination(10, TimeUnit.MINUTES); + + } + + public void testBrokers() throws Exception { + + buildUrlList(); + + for (int i = 0; i < numBrokers; i++) { + createBroker(i); + } + + startAllBrokers(); + waitForBridgeFormation(numBrokers - 1); + + verifyPeerBrokerInfos(numBrokers - 1); + + + final List consumerStates = startAllGWConsumers(numBrokers); + + startAllGWFanoutConsumers(numBrokers); + + LOG.info("Waiting for percolation of consumers.."); + TimeUnit.SECONDS.sleep(5); + + LOG.info("Produce mesages.."); + long startTime = System.currentTimeMillis(); + + // produce + produce(numMessages); + + assertTrue("Got all sent", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + for (ConsumerState tally : consumerStates) { + final int expected = numMessages * (tally.destination.isComposite() ? tally.destination.getCompositeDestinations().length : 1); + LOG.info("Tally for: " + tally.brokerName + ", dest: " + tally.destination + " - " + tally.accumulator.get()); + if (tally.accumulator.get() != expected) { + LOG.info("Tally for: " + tally.brokerName + ", dest: " + tally.destination + " - " + tally.accumulator.get() + " != " + expected + ", " + tally.expected); + if (tally.accumulator.get() > expected - 50) { + dumpQueueStat(null); + } + if (tally.expected.size() == 1) { + startConsumer(tally.brokerName, tally.destination); + }; + return false; + } + LOG.info("got tally on " + tally.brokerName); + } + return true; + } + }, 1000 * 60 * 1000l, 20*1000)); + + assertTrue("No exceptions:" + exceptions, exceptions.isEmpty()); + + LOG.info("done"); + long duration = System.currentTimeMillis() - startTime; + LOG.info("Duration:" + TimeUtils.printDuration(duration)); + + assertEquals("nothing in the dlq's", 0, dumpQueueStat(new ActiveMQQueue("ActiveMQ.DLQ"))); + + } + + private void startConsumer(String brokerName, ActiveMQDestination destination) throws Exception { + int id = Integer.parseInt(brokerName.substring(1)); + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:" + (portBase + id)); + connectionFactory.setWatchTopicAdvisories(false); + QueueConnection queueConnection = connectionFactory.createQueueConnection(); + queueConnection.start(); + + queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(destination); + queueConnection.close(); + } + + private long dumpQueueStat(ActiveMQDestination destination) throws Exception { + long sumTotal = 0; + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext(); ) { + BrokerService brokerService = i.next().broker; + for (ObjectName objectName : brokerService.getAdminView().getQueues()) { + if (destination != null && objectName.toString().contains(destination.getPhysicalName())) { + QueueViewMBean qViewMBean = (QueueViewMBean) brokerService.getManagementContext().newProxyInstance(objectName, QueueViewMBean.class, false); + LOG.info(brokerService.getBrokerName() + ", " + qViewMBean.getName() + ", Enqueue:" + qViewMBean.getEnqueueCount() + ", Size: " + qViewMBean.getQueueSize()); + sumTotal += qViewMBean.getQueueSize(); + } + } + } + return sumTotal; + } + + private void startAllGWFanoutConsumers(int nBrokers) throws Exception { + + StringBuffer compositeDest = new StringBuffer(); + for (int k = 0; k < nBrokers; k++) { + compositeDest.append("GW." + k); + if (k + 1 != nBrokers) { + compositeDest.append(','); + } + } + ActiveMQQueue compositeQ = new ActiveMQQueue(compositeDest.toString()); + + for (int id = 0; id < nBrokers; id++) { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:" + (portBase + id) + ")"); + connectionFactory.setWatchTopicAdvisories(false); + + QueueConnection queueConnection = connectionFactory.createQueueConnection(); + queueConnection.start(); + + final QueueSession queueSession = queueConnection.createQueueSession(true, Session.SESSION_TRANSACTED); + + final MessageProducer producer = queueSession.createProducer(compositeQ); + queueSession.createReceiver(new ActiveMQQueue("IN")).setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + producer.send(message); + queueSession.commit(); + } catch (Exception e) { + LOG.error("Failed to fanout to GW: " + message, e); + } + + } + }); + } + } + + private List startAllGWConsumers(int nBrokers) throws Exception { + List consumerStates = new LinkedList(); + for (int id = 0; id < nBrokers; id++) { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:" + (portBase + id) + ")"); + connectionFactory.setWatchTopicAdvisories(false); + + QueueConnection queueConnection = connectionFactory.createQueueConnection(); + queueConnection.start(); + + final QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQQueue destination = new ActiveMQQueue("GW." + id); + QueueReceiver queueReceiver = queueSession.createReceiver(destination); + + final ConsumerState consumerState = new ConsumerState(); + consumerState.brokerName = ((ActiveMQConnection) queueConnection).getBrokerName(); + consumerState.receiver = queueReceiver; + consumerState.destination = destination; + for (int j = 0; j < numMessages * (consumerState.destination.isComposite() ? consumerState.destination.getCompositeDestinations().length : 1); j++) { + consumerState.expected.add(j); + } + + if (!accumulators.containsKey(destination)) { + accumulators.put(destination, new AtomicInteger(0)); + } + consumerState.accumulator = accumulators.get(destination); + + queueReceiver.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + if (consumerSleepTime > 0) { + TimeUnit.MILLISECONDS.sleep(consumerSleepTime); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + consumerState.accumulator.incrementAndGet(); + try { + consumerState.expected.remove(((ActiveMQMessage) message).getProperty("NUM")); + } catch (IOException e) { + e.printStackTrace(); + } + //queueSession.commit(); + } catch (Exception e) { + LOG.error("Failed to commit slow receipt of " + message, e); + } + } + }); + + consumerStates.add(consumerState); + + } + return consumerStates; + } + + private void produce(final int numMessages) throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(numProducers); + final AtomicInteger toSend = new AtomicInteger(numMessages); + for (int i = 1; i <= numProducers; i++) { + final int id = i % numBrokers; + executorService.execute(new Runnable() { + @Override + public void run() { + try { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:" + (portBase + id) + ")"); + connectionFactory.setWatchTopicAdvisories(false); + QueueConnection queueConnection = connectionFactory.createQueueConnection(); + queueConnection.start(); + QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = queueSession.createProducer(null); + int val = 0; + while ((val = toSend.decrementAndGet()) >= 0) { + + int id = numMessages - val - 1; + + ActiveMQQueue compositeQ = new ActiveMQQueue("IN"); + Message textMessage = queueSession.createTextMessage(((ActiveMQConnection) queueConnection).getBrokerName() + "->" + id + " payload:" + payload); + textMessage.setIntProperty("NUM", id); + producer.send(compositeQ, textMessage); + } + queueConnection.close(); + + } catch (Throwable throwable) { + throwable.printStackTrace(); + exceptions.add(throwable); + } + } + }); + } + } + + private void verifyPeerBrokerInfo(BrokerItem brokerItem, final int max) throws Exception { + final BrokerService broker = brokerItem.broker; + final RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("verify infos " + broker.getBrokerName() + ", len: " + regionBroker.getPeerBrokerInfos().length); + return max == regionBroker.getPeerBrokerInfos().length; + } + }); + LOG.info("verify infos " + broker.getBrokerName() + ", len: " + regionBroker.getPeerBrokerInfos().length); + List missing = new ArrayList(); + for (int i = 0; i < max; i++) { + missing.add("B" + i); + } + if (max != regionBroker.getPeerBrokerInfos().length) { + for (BrokerInfo info : regionBroker.getPeerBrokerInfos()) { + LOG.info(info.getBrokerName()); + missing.remove(info.getBrokerName()); + } + LOG.info("Broker infos off.." + missing); + } + assertEquals(broker.getBrokerName(), max, regionBroker.getPeerBrokerInfos().length); + } + + private void verifyPeerBrokerInfos(final int max) throws Exception { + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext(); ) { + verifyPeerBrokerInfo(i.next(), max); + } + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + class ConsumerState { + AtomicInteger accumulator; + String brokerName; + QueueReceiver receiver; + ActiveMQDestination destination; + ConcurrentLinkedQueue expected = new ConcurrentLinkedQueue(); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485NetworkOfXBrokersWithNDestsFanoutTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485NetworkOfXBrokersWithNDestsFanoutTransactionTest.java new file mode 100644 index 0000000000..c2cf53ae2a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485NetworkOfXBrokersWithNDestsFanoutTransactionTest.java @@ -0,0 +1,353 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.QueueConnection; +import javax.jms.QueueReceiver; +import javax.jms.QueueSession; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.TimeUtils; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4485NetworkOfXBrokersWithNDestsFanoutTransactionTest extends JmsMultipleBrokersTestSupport { + static final String payload = new String(new byte[10 * 1024]); + private static final Logger LOG = LoggerFactory.getLogger(AMQ4485NetworkOfXBrokersWithNDestsFanoutTransactionTest.class); + final int portBase = 61600; + final int numBrokers = 4; + final int numProducers = 10; + final int numMessages = 800; + final int consumerSleepTime = 20; + StringBuilder brokersUrl = new StringBuilder(); + HashMap accumulators = new HashMap(); + private ArrayList exceptions = new ArrayList(); + + protected void buildUrlList() throws Exception { + for (int i = 0; i < numBrokers; i++) { + brokersUrl.append("tcp://localhost:" + (portBase + i)); + if (i != numBrokers - 1) { + brokersUrl.append(','); + } + } + } + + protected BrokerService createBroker(int brokerid) throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(true); + broker.getManagementContext().setCreateConnector(false); + + + broker.setUseJmx(true); + broker.setBrokerName("B" + brokerid); + broker.addConnector(new URI("tcp://localhost:" + (portBase + brokerid))); + + addNetworkConnector(broker); + broker.setSchedulePeriodForDestinationPurge(0); + broker.getSystemUsage().setSendFailIfNoSpace(true); + broker.getSystemUsage().getMemoryUsage().setLimit(512 * 1024 * 1024); + + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setExpireMessagesPeriod(0); + policyEntry.setQueuePrefetch(1000); + policyEntry.setMemoryLimit(1024 * 1024l); + policyEntry.setOptimizedDispatch(false); + policyEntry.setProducerFlowControl(false); + policyEntry.setEnableAudit(true); + policyEntry.setUseCache(true); + policyMap.put(new ActiveMQQueue("GW.>"), policyEntry); + broker.setDestinationPolicy(policyMap); + + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + kahaDBPersistenceAdapter.setConcurrentStoreAndDispatchQueues(false); + + brokers.put(broker.getBrokerName(), new BrokerItem(broker)); + return broker; + } + + private void addNetworkConnector(BrokerService broker) throws Exception { + StringBuilder networkConnectorUrl = new StringBuilder("static:(").append(brokersUrl.toString()); + networkConnectorUrl.append(')'); + + for (int i = 0; i < 2; i++) { + NetworkConnector nc = new DiscoveryNetworkConnector(new URI(networkConnectorUrl.toString())); + nc.setName("Bridge-" + i); + nc.setNetworkTTL(1); + nc.setDecreaseNetworkConsumerPriority(true); + nc.setDynamicOnly(true); + nc.setPrefetchSize(100); + nc.setDynamicallyIncludedDestinations( + Arrays.asList(new ActiveMQDestination[]{new ActiveMQQueue("GW.*")})); + broker.addNetworkConnector(nc); + } + } + + public void testBrokers() throws Exception { + + buildUrlList(); + + for (int i = 0; i < numBrokers; i++) { + createBroker(i); + } + + startAllBrokers(); + waitForBridgeFormation(numBrokers - 1); + + verifyPeerBrokerInfos(numBrokers - 1); + + + final List consumerStates = startAllGWConsumers(numBrokers); + + startAllGWFanoutConsumers(numBrokers); + + LOG.info("Waiting for percolation of consumers.."); + TimeUnit.SECONDS.sleep(5); + + LOG.info("Produce mesages.."); + long startTime = System.currentTimeMillis(); + + // produce + produce(numMessages); + + assertTrue("Got all sent", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + for (ConsumerState tally : consumerStates) { + final int expected = numMessages * (tally.destination.isComposite() ? tally.destination.getCompositeDestinations().length : 1); + LOG.info("Tally for: " + tally.brokerName + ", dest: " + tally.destination + " - " + tally.accumulator.get()); + if (tally.accumulator.get() != expected) { + LOG.info("Tally for: " + tally.brokerName + ", dest: " + tally.destination + " - " + tally.accumulator.get() + " != " + expected + ", " + tally.expected); + return false; + } + LOG.info("got tally on " + tally.brokerName); + } + return true; + } + }, 1000 * 60 * 1000l)); + + assertTrue("No exceptions:" + exceptions, exceptions.isEmpty()); + + LOG.info("done"); + long duration = System.currentTimeMillis() - startTime; + LOG.info("Duration:" + TimeUtils.printDuration(duration)); + } + + private void startAllGWFanoutConsumers(int nBrokers) throws Exception { + + StringBuffer compositeDest = new StringBuffer(); + for (int k = 0; k < nBrokers; k++) { + compositeDest.append("GW." + k); + if (k + 1 != nBrokers) { + compositeDest.append(','); + } + } + ActiveMQQueue compositeQ = new ActiveMQQueue(compositeDest.toString()); + + for (int id = 0; id < nBrokers; id++) { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:" + (portBase + id) + ")"); + connectionFactory.setWatchTopicAdvisories(false); + + QueueConnection queueConnection = connectionFactory.createQueueConnection(); + queueConnection.start(); + + final QueueSession queueSession = queueConnection.createQueueSession(true, Session.SESSION_TRANSACTED); + + final MessageProducer producer = queueSession.createProducer(compositeQ); + queueSession.createReceiver(new ActiveMQQueue("IN")).setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + producer.send(message); + queueSession.commit(); + } catch (Exception e) { + LOG.error("Failed to fanout to GW: " + message, e); + } + + } + }); + } + } + + private List startAllGWConsumers(int nBrokers) throws Exception { + List consumerStates = new LinkedList(); + for (int id = 0; id < nBrokers; id++) { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:" + (portBase + id) + ")"); + connectionFactory.setWatchTopicAdvisories(false); + + QueueConnection queueConnection = connectionFactory.createQueueConnection(); + queueConnection.start(); + + final QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQQueue destination = new ActiveMQQueue("GW." + id); + QueueReceiver queueReceiver = queueSession.createReceiver(destination); + + final ConsumerState consumerState = new ConsumerState(); + consumerState.brokerName = ((ActiveMQConnection) queueConnection).getBrokerName(); + consumerState.receiver = queueReceiver; + consumerState.destination = destination; + for (int j = 0; j < numMessages * (consumerState.destination.isComposite() ? consumerState.destination.getCompositeDestinations().length : 1); j++) { + consumerState.expected.add(j); + } + + if (!accumulators.containsKey(destination)) { + accumulators.put(destination, new AtomicInteger(0)); + } + consumerState.accumulator = accumulators.get(destination); + + queueReceiver.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + if (consumerSleepTime > 0) { + TimeUnit.MILLISECONDS.sleep(consumerSleepTime); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + consumerState.accumulator.incrementAndGet(); + try { + consumerState.expected.remove(((ActiveMQMessage) message).getProperty("NUM")); + } catch (IOException e) { + e.printStackTrace(); + } + } catch (Exception e) { + LOG.error("Failed to commit slow receipt of " + message, e); + } + } + }); + + consumerStates.add(consumerState); + + } + return consumerStates; + } + + private void produce(int numMessages) throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(numProducers); + final AtomicInteger toSend = new AtomicInteger(numMessages); + for (int i = 1; i <= numProducers; i++) { + final int id = i % numBrokers; + executorService.execute(new Runnable() { + @Override + public void run() { + try { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:" + (portBase + id) + ")"); + connectionFactory.setWatchTopicAdvisories(false); + QueueConnection queueConnection = connectionFactory.createQueueConnection(); + queueConnection.start(); + QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = queueSession.createProducer(null); + int val = 0; + while ((val = toSend.decrementAndGet()) >= 0) { + + ActiveMQQueue compositeQ = new ActiveMQQueue("IN"); + LOG.info("Send to: " + ((ActiveMQConnection) queueConnection).getBrokerName() + ", " + val + ", dest:" + compositeQ); + Message textMessage = queueSession.createTextMessage(((ActiveMQConnection) queueConnection).getBrokerName() + "->" + val + " payload:" + payload); + textMessage.setIntProperty("NUM", val); + producer.send(compositeQ, textMessage); + } + queueConnection.close(); + + } catch (Throwable throwable) { + throwable.printStackTrace(); + exceptions.add(throwable); + } + } + }); + } + } + + private void verifyPeerBrokerInfo(BrokerItem brokerItem, final int max) throws Exception { + final BrokerService broker = brokerItem.broker; + final RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("verify infos " + broker.getBrokerName() + ", len: " + regionBroker.getPeerBrokerInfos().length); + return max == regionBroker.getPeerBrokerInfos().length; + } + }); + LOG.info("verify infos " + broker.getBrokerName() + ", len: " + regionBroker.getPeerBrokerInfos().length); + List missing = new ArrayList(); + for (int i = 0; i < max; i++) { + missing.add("B" + i); + } + if (max != regionBroker.getPeerBrokerInfos().length) { + for (BrokerInfo info : regionBroker.getPeerBrokerInfos()) { + LOG.info(info.getBrokerName()); + missing.remove(info.getBrokerName()); + } + LOG.info("Broker infos off.." + missing); + } + assertEquals(broker.getBrokerName(), max, regionBroker.getPeerBrokerInfos().length); + } + + private void verifyPeerBrokerInfos(final int max) throws Exception { + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext(); ) { + verifyPeerBrokerInfo(i.next(), max); + } + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + class ConsumerState { + AtomicInteger accumulator; + String brokerName; + QueueReceiver receiver; + ActiveMQDestination destination; + Vector expected = new Vector(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485Test.java new file mode 100644 index 0000000000..1126d310e3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4485Test.java @@ -0,0 +1,197 @@ +/** + * 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.bugs; + +import java.util.HashSet; +import java.util.Set; +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.broker.TransactionBroker; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQBytesMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.transaction.Synchronization; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4485Test extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(AMQ4485Test.class); + BrokerService broker; + ActiveMQConnectionFactory factory; + final int messageCount = 20; + int memoryLimit = 40 * 1024; + final ActiveMQQueue destination = new ActiveMQQueue("QUEUE." + this.getClass().getName()); + final Vector exceptions = new Vector(); + final CountDownLatch slowSendResume = new CountDownLatch(1); + + + protected void configureBroker(long memoryLimit) throws Exception { + broker.setDeleteAllMessagesOnStartup(true); + broker.setAdvisorySupport(false); + + PolicyEntry policy = new PolicyEntry(); + policy.setExpireMessagesPeriod(0); + policy.setMemoryLimit(memoryLimit); + policy.setProducerFlowControl(false); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + + broker.setPlugins(new BrokerPlugin[] {new BrokerPluginSupport() { + @Override + public void send(ProducerBrokerExchange producerExchange, final Message messageSend) throws Exception { + if (messageSend.isInTransaction() && messageSend.getProperty("NUM") != null) { + final Integer num = (Integer) messageSend.getProperty("NUM"); + if (true) { + TransactionBroker transactionBroker = (TransactionBroker)broker.getBroker().getAdaptor(TransactionBroker.class); + transactionBroker.getTransaction(producerExchange.getConnectionContext(), messageSend.getTransactionId(), false).addSynchronization( + new Synchronization() { + public void afterCommit() throws Exception { + LOG.error("AfterCommit, NUM:" + num + ", " + messageSend.getMessageId() + ", tx: " + messageSend.getTransactionId()); + if (num == 5) { + // we want to add to cursor after usage is exhausted by message 20 and when + // all other messages have been processed + LOG.error("Pausing on latch in afterCommit for: " + num + ", " + messageSend.getMessageId()); + slowSendResume.await(20, TimeUnit.SECONDS); + LOG.error("resuming on latch afterCommit for: " + num + ", " + messageSend.getMessageId()); + } else if (messageCount + 1 == num) { + LOG.error("releasing latch. " + num + ", " + messageSend.getMessageId()); + slowSendResume.countDown(); + // for message X, we need to delay so message 5 can setBatch + TimeUnit.SECONDS.sleep(5); + LOG.error("resuming afterCommit for: " + num + ", " + messageSend.getMessageId()); + } + } + }); + } + } + super.send(producerExchange, messageSend); + } + } + }); + + } + + + public void testOutOfOrderTransactionCompletionOnMemoryLimit() throws Exception { + + Set expected = new HashSet(); + final Vector sessionVector = new Vector(); + ExecutorService executorService = Executors.newCachedThreadPool(); + for (int i = 1; i <= messageCount; i++) { + sessionVector.add(send(i, 1, true)); + expected.add(i); + } + + // get parallel commit so that the sync writes are batched + for (int i = 0; i < messageCount; i++) { + final int id = i; + executorService.submit(new Runnable() { + @Override + public void run() { + try { + sessionVector.get(id).commit(); + } catch (Exception fail) { + exceptions.add(fail); + } + } + }); + } + + final DestinationViewMBean queueViewMBean = (DestinationViewMBean) + broker.getManagementContext().newProxyInstance(broker.getAdminView().getQueues()[0], DestinationViewMBean.class, false); + + // not sure how many messages will get enqueued + TimeUnit.SECONDS.sleep(3); + if (false) + assertTrue("all " + messageCount + " on the q", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("enqueueCount: " + queueViewMBean.getEnqueueCount()); + return messageCount == queueViewMBean.getEnqueueCount(); + } + })); + + LOG.info("Big send to blow available destination usage before slow send resumes"); + send(messageCount + 1, 35*1024, true).commit(); + + + // consume and verify all received + Connection cosumerConnection = factory.createConnection(); + cosumerConnection.start(); + MessageConsumer consumer = cosumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(destination); + for (int i = 1; i <= messageCount + 1; i++) { + BytesMessage bytesMessage = (BytesMessage) consumer.receive(10000); + assertNotNull("Got message: " + i + ", " + expected, bytesMessage); + MessageId mqMessageId = ((ActiveMQBytesMessage) bytesMessage).getMessageId(); + LOG.info("got: " + expected + ", " + mqMessageId + ", NUM=" + ((ActiveMQBytesMessage) bytesMessage).getProperty("NUM")); + expected.remove(((ActiveMQBytesMessage) bytesMessage).getProperty("NUM")); + } + } + + private Session send(int id, int messageSize, boolean transacted) throws Exception { + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(transacted, transacted ? Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + BytesMessage bytesMessage = session.createBytesMessage(); + bytesMessage.writeBytes(new byte[messageSize]); + bytesMessage.setIntProperty("NUM", id); + producer.send(bytesMessage); + LOG.info("Sent:" + bytesMessage.getJMSMessageID() + " session tx: " + ((ActiveMQBytesMessage) bytesMessage).getTransactionId()); + return session; + } + + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + broker.setBrokerName("thisOne"); + configureBroker(memoryLimit); + broker.start(); + factory = new ActiveMQConnectionFactory("vm://thisOne?jms.alwaysSyncSend=true"); + factory.setWatchTopicAdvisories(false); + + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + broker = null; + } + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4487Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4487Test.java new file mode 100644 index 0000000000..346650e7c1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4487Test.java @@ -0,0 +1,135 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Enumeration; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4487Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4487Test.class); + + private final String destinationName = "TEST.QUEUE"; + private BrokerService broker; + private ActiveMQConnectionFactory factory; + + @Before + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.deleteAllMessages(); + broker.setUseJmx(false); + broker.setAdvisorySupport(false); + + PolicyEntry policy = new PolicyEntry(); + policy.setQueue(">"); + policy.setMaxProducersToAudit(75); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + + broker.start(); + broker.waitUntilStarted(); + factory = new ActiveMQConnectionFactory("vm://localhost"); + } + + @After + public void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + private void sendMessages(int messageToSend) throws Exception { + String data = ""; + for (int i = 0; i < 1024 * 2; i++) { + data += "x"; + } + + Connection connection = factory.createConnection(); + connection.start(); + + for (int i = 0; i < messageToSend; i++) { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(destinationName); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage(data)); + session.close(); + } + + connection.close(); + } + + @Test + public void testBrowsingWithLessThanMaxAuditDepth() throws Exception { + doTestBrowsing(75); + } + + @Test + public void testBrowsingWithMoreThanMaxAuditDepth() throws Exception { + doTestBrowsing(300); + } + + @SuppressWarnings("rawtypes") + private void doTestBrowsing(int messagesToSend) throws Exception { + + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(destinationName); + + sendMessages(messagesToSend); + + QueueBrowser browser = session.createBrowser(queue); + Enumeration enumeration = browser.getEnumeration(); + int received = 0; + while (enumeration.hasMoreElements()) { + Message m = (Message) enumeration.nextElement(); + assertNotNull(m); + + if (LOG.isDebugEnabled()) { + LOG.debug("Browsed Message: {}", m.getJMSMessageID()); + } + + received++; + if (received > messagesToSend) { + break; + } + } + + browser.close(); + + assertEquals(messagesToSend, received); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4504Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4504Test.java new file mode 100644 index 0000000000..64204bd758 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4504Test.java @@ -0,0 +1,82 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +import static org.junit.Assert.assertNotNull; + +public class AMQ4504Test { + + BrokerService brokerService; + + @Before + public void setup() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.start(); + } + + @After + public void stop() throws Exception { + brokerService.stop(); + } + + @Test + public void testCompositeDestConsumer() throws Exception { + + final int numDests = 20; + final int numMessages = 200; + StringBuffer stringBuffer = new StringBuffer(); + for (int i=0; i"); + MessageConsumer consumer = session.createConsumer(dlqDestination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + advised.set(true); + } + }); + connection.start(); + + ExecutorService service = Executors.newSingleThreadExecutor(); + + service.execute(new Runnable() { + @Override + public void run() { + try { + ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTemporaryQueue(); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.setTimeToLive(400); + producer.send(session.createTextMessage()); + producer.send(session.createTextMessage()); + TimeUnit.MILLISECONDS.sleep(500); + connection.close(); + } catch (Exception e) { + } + } + }); + + service.shutdown(); + assertTrue(service.awaitTermination(1, TimeUnit.MINUTES)); + assertFalse("Should not get any Advisories for DLQ'd Messages", advised.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4518Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4518Test.java new file mode 100644 index 0000000000..e5446422ee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4518Test.java @@ -0,0 +1,128 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.IndividualDeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ4518Test { + + private BrokerService brokerService; + private String connectionUri; + + @Before + public void setup() throws Exception { + brokerService = new BrokerService(); + + connectionUri = brokerService.addConnector("tcp://localhost:0").getPublishableConnectString(); + + // Configure Dead Letter Strategy + DeadLetterStrategy strategy = new IndividualDeadLetterStrategy(); + ((IndividualDeadLetterStrategy)strategy).setUseQueueForQueueMessages(true); + ((IndividualDeadLetterStrategy)strategy).setQueuePrefix("DLQ."); + strategy.setProcessNonPersistent(false); + strategy.setProcessExpired(false); + + // Add policy and individual DLQ strategy + PolicyEntry policy = new PolicyEntry(); + policy.setTimeBeforeDispatchStarts(3000); + policy.setDeadLetterStrategy(strategy); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + + brokerService.setDestinationPolicy(pMap); + brokerService.setPersistent(false); + brokerService.start(); + } + + @After + public void stop() throws Exception { + brokerService.stop(); + } + + @Test(timeout=360000) + public void test() throws Exception { + + final ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(connectionUri); + + final AtomicBoolean advised = new AtomicBoolean(false); + Connection connection = cf.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dlqDestination = session.createTopic(AdvisorySupport.EXPIRED_QUEUE_MESSAGES_TOPIC_PREFIX + ">"); + MessageConsumer consumer = session.createConsumer(dlqDestination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + advised.set(true); + } + }); + connection.start(); + + ExecutorService service = Executors.newSingleThreadExecutor(); + + service.execute(new Runnable() { + @Override + public void run() { + try { + ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTemporaryQueue(); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.setTimeToLive(400); + producer.send(session.createTextMessage()); + producer.send(session.createTextMessage()); + TimeUnit.MILLISECONDS.sleep(500); + connection.close(); + } catch (Exception e) { + } + } + }); + + service.shutdown(); + assertTrue(service.awaitTermination(1, TimeUnit.MINUTES)); + assertFalse("Should not get any Advisories for Expired Messages", advised.get()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4530Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4530Test.java new file mode 100644 index 0000000000..e8ab9f4299 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4530Test.java @@ -0,0 +1,116 @@ +/** + * 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.bugs; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularDataSupport; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.CompositeDataConstants; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ4530Test { + + private static BrokerService brokerService; + private static String TEST_QUEUE = "testQueue"; + private static ActiveMQQueue queue = new ActiveMQQueue(TEST_QUEUE); + private static String BROKER_ADDRESS = "tcp://localhost:0"; + private static String KEY = "testproperty"; + private static String VALUE = "propvalue"; + + private ActiveMQConnectionFactory connectionFactory; + private String connectionUri; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + brokerService.waitUntilStarted(); + + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + sendMessage(); + } + + public void sendMessage() throws Exception { + final Connection conn = connectionFactory.createConnection(); + try { + conn.start(); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Destination queue = session.createQueue(TEST_QUEUE); + final Message toSend = session.createMessage(); + toSend.setStringProperty(KEY, VALUE); + final MessageProducer producer = session.createProducer(queue); + producer.send(queue, toSend); + } finally { + conn.close(); + } + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @SuppressWarnings("unchecked") + @Test + public void testStringPropertiesFromCompositeData() throws Exception { + final QueueViewMBean queueView = getProxyToQueueViewMBean(); + final CompositeData message = queueView.browse()[0]; + assertNotNull(message); + TabularDataSupport stringProperties = (TabularDataSupport) message.get(CompositeDataConstants.STRING_PROPERTIES); + assertNotNull(stringProperties); + assertThat(stringProperties.size(), is(greaterThan(0))); + Map.Entry compositeDataEntry = (Map.Entry) stringProperties.entrySet().toArray()[0]; + CompositeData stringEntry = (CompositeData) compositeDataEntry.getValue(); + assertThat(String.valueOf(stringEntry.get("key")), equalTo(KEY)); + assertThat(String.valueOf(stringEntry.get("value")), equalTo(VALUE)); + } + + private QueueViewMBean getProxyToQueueViewMBean() throws MalformedObjectNameException, NullPointerException, + JMSException { + final ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queue.getQueueName()); + final QueueViewMBean proxy = (QueueViewMBean) brokerService.getManagementContext().newProxyInstance( + queueViewMBeanName, QueueViewMBean.class, true); + return proxy; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4531Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4531Test.java new file mode 100644 index 0000000000..0be3226582 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4531Test.java @@ -0,0 +1,144 @@ +/** + * 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.bugs; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.management.ManagementFactory; +import java.util.concurrent.CountDownLatch; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Unit test for simple App. + */ +public class AMQ4531Test extends TestCase { + + private final Logger LOG = LoggerFactory.getLogger(AMQ4531Test.class); + + private String connectionURI; + private MBeanServer mbeanServer; + private BrokerService broker; + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + connectionURI = broker.addConnector("tcp://0.0.0.0:0?maximumConnections=1").getPublishableConnectString(); + broker.setPersistent(false); + broker.start(); + mbeanServer = ManagementFactory.getPlatformMBeanServer(); + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + super.tearDown(); + } + + /** + * Create the test case + * + * @param testName + * name of the test case + */ + public AMQ4531Test(String testName) { + super(testName); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() { + return new TestSuite(AMQ4531Test.class); + } + + public void testFDSLeak() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionURI); + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.start(); + + int connections = 100; + final long original = openFileDescriptorCount(); + LOG.info("FD count: " + original); + final CountDownLatch done = new CountDownLatch(connections); + for (int i = 0; i < connections; i++) { + new Thread("worker: " + i) { + @Override + public void run() { + ActiveMQConnection connection = null; + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionURI); + connection = (ActiveMQConnection) factory.createConnection(); + connection.start(); + } catch (Exception e) { + LOG.debug(getStack(e)); + } finally { + try { + connection.close(); + } catch (Exception e) { + LOG.debug(getStack(e)); + } + done.countDown(); + LOG.debug("Latch count down called."); + } + } + }.start(); + } + + // Wait for all the clients to finish + LOG.info("Waiting for latch..."); + done.await(); + LOG.info("Latch complete."); + LOG.info("FD count: " + openFileDescriptorCount()); + + assertTrue("Too many open file descriptors: " + openFileDescriptorCount(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + long openFDs = openFileDescriptorCount(); + LOG.info("Current FD count [{}], original FD count[{}]", openFDs, original); + return (openFDs - original) < 10; + } + })); + } + + private long openFileDescriptorCount() throws Exception { + return ((Long) mbeanServer.getAttribute(new ObjectName("java.lang:type=OperatingSystem"), "OpenFileDescriptorCount")).longValue(); + } + + private String getStack(Throwable aThrowable) { + final Writer result = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(result); + aThrowable.printStackTrace(printWriter); + return result.toString(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4554Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4554Test.java new file mode 100644 index 0000000000..47ce6421ec --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4554Test.java @@ -0,0 +1,107 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Unit test for simple App. + */ +public class AMQ4554Test extends TestCase { + + private final Logger LOG = LoggerFactory.getLogger(AMQ4554Test.class); + + private String connectionURI; + private BrokerService broker; + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + connectionURI = broker.addConnector("tcp://0.0.0.0:0?maximumConnections=1").getPublishableConnectString(); + broker.setPersistent(false); + broker.start(); + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + super.tearDown(); + } + + /** + * Create the test case + * + * @param testName + * name of the test case + */ + public AMQ4554Test(String testName) { + super(testName); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() { + return new TestSuite(AMQ4554Test.class); + } + + public void testMSXProducerTXID() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionURI); + Connection connection = factory.createConnection(); + connection.start(); + + Session producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = producerSession.createProducer(producerSession.createQueue("myQueue")); + TextMessage producerMessage = producerSession.createTextMessage("Test Message"); + producer.send(producerMessage); + producer.close(); + producerSession.commit(); + producerSession.close(); + + Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = consumerSession.createConsumer(consumerSession.createQueue("myQueue")); + Message consumerMessage = consumer.receive(1000); + try { + String txId = consumerMessage.getStringProperty("JMSXProducerTXID"); + assertNotNull(txId); + } catch(Exception e) { + LOG.info("Caught Exception that was not expected:", e); + fail("Should not throw"); + } + consumer.close(); + consumerSession.commit(); + consumerSession.close(); + connection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4582Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4582Test.java new file mode 100644 index 0000000000..1c34982098 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4582Test.java @@ -0,0 +1,91 @@ +/** + * 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.bugs; + +import java.io.IOException; + +import javax.jms.Connection; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.ConsumerThread; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4582Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ4582Test.class); + + BrokerService broker; + Connection connection; + Session session; + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/server.keystore"; + public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore"; + + public static final int PRODUCER_COUNT = 10; + public static final int CONSUMER_COUNT = 10; + public static final int MESSAGE_COUNT = 1000; + + final ConsumerThread[] consumers = new ConsumerThread[CONSUMER_COUNT]; + + @Before + public void setUp() throws Exception { + System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStore", SERVER_KEYSTORE); + System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + try { + broker.stop(); + } catch(Exception e) {} + } + } + + @Rule public ExpectedException thrown = ExpectedException.none(); + @Test + public void simpleTest() throws Exception { + thrown.expect(IOException.class); + thrown.expectMessage("enabledCipherSuites=BADSUITE"); + + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + try { + broker.addConnector( + "ssl://localhost:0?transport.needClientAuth=true&transport.enabledCipherSuites=BADSUITE"); + broker.start(); + broker.waitUntilStarted(); + } catch (Exception e) { + LOG.info("BrokerService threw:", e); + throw e; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4595Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4595Test.java new file mode 100644 index 0000000000..507e52e776 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4595Test.java @@ -0,0 +1,158 @@ +/** + * 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.bugs; + +import java.net.URI; +import java.util.Date; +import java.util.Enumeration; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnection; +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.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; + +public class AMQ4595Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4595Test.class); + + private BrokerService broker; + private URI connectUri; + private ActiveMQConnectionFactory factory; + + @Before + public void startBroker() throws Exception { + broker = new BrokerService(); + TransportConnector connector = broker.addConnector("vm://localhost"); + broker.deleteAllMessages(); + + //PolicyMap pMap = new PolicyMap(); + //PolicyEntry policyEntry = new PolicyEntry(); + //policyEntry.setMaxBrowsePageSize(10000); + //pMap.put(new ActiveMQQueue(">"), policyEntry); + // when no policy match, browserSub has maxMessages==0 + //broker.setDestinationPolicy(pMap); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.start(); + broker.waitUntilStarted(); + connectUri = connector.getConnectUri(); + factory = new ActiveMQConnectionFactory(connectUri); + } + + @After + public void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test(timeout=120000) + public void testBrowsingSmallBatch() throws JMSException { + doTestBrowsing(100); + } + + @Test(timeout=160000) + public void testBrowsingMediumBatch() throws JMSException { + doTestBrowsing(1000); + } + + @Test(timeout=300000) + public void testBrowsingLargeBatch() throws JMSException { + doTestBrowsing(10000); + } + + private void doTestBrowsing(int messageToSend) throws JMSException { + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + + // Send the messages to the Queue. + ActiveMQConnection producerConnection = (ActiveMQConnection) factory.createConnection(); + producerConnection.setUseAsyncSend(true); + producerConnection.start(); + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + for (int i = 1; i <= messageToSend; i++) { + String msgStr = provideMessageText(i, 8192); + producer.send(producerSession.createTextMessage(msgStr)); + if ((i % 1000) == 0) { + LOG.info("P&C: {}", msgStr.substring(0, 100)); + } + } + producerConnection.close(); + + LOG.info("Mem usage after producer done: " + broker.getSystemUsage().getMemoryUsage().getPercentUsage() + "%"); + + // Browse the queue. + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + QueueBrowser browser = session.createBrowser(queue); + Enumeration enumeration = browser.getEnumeration(); + int browsed = 0; + while (enumeration.hasMoreElements()) { + TextMessage m = (TextMessage) enumeration.nextElement(); + browsed++; + if ((browsed % 1000) == 0) { + LOG.info("B[{}]: {}", browsed, m.getText().substring(0, 100)); + } + } + browser.close(); + session.close(); + connection.close(); + + LOG.info("Mem usage after browser closed: " + broker.getSystemUsage().getMemoryUsage().getPercentUsage() + "%"); + + // The number of messages browsed should be equal to the number of messages sent. + assertEquals(messageToSend, browsed); + + browser.close(); + } + + public String provideMessageText(int messageNumber, int messageSize) { + StringBuilder buf = new StringBuilder(); + buf.append("Message: "); + if (messageNumber > 0) { + buf.append(messageNumber); + } + buf.append(" sent at: ").append(new Date()); + + if (buf.length() > messageSize) { + return buf.substring(0, messageSize); + } + for (int i = buf.length(); i < messageSize; i++) { + buf.append(' '); + } + return buf.toString(); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4607Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4607Test.java new file mode 100644 index 0000000000..265b692e6f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4607Test.java @@ -0,0 +1,246 @@ +/** + * 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.bugs; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import junit.framework.Test; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.network.ConditionalNetworkBridgeFilterFactory; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4607Test extends JmsMultipleBrokersTestSupport implements UncaughtExceptionHandler { + private static final Logger LOG = LoggerFactory.getLogger(AMQ4607Test.class); + + public static final int BROKER_COUNT = 3; + public static final int CONSUMER_COUNT = 1; + public static final int MESSAGE_COUNT = 0; + public static final boolean CONDUIT = true; + public static final int TIMEOUT = 20000; + + public boolean duplex = true; + protected Map consumerMap; + Map unhandeledExceptions = new HashMap(); + + private void assertNoUnhandeledExceptions() { + for( Entry e: unhandeledExceptions.entrySet()) { + LOG.error("Thread:" + e.getKey() + " Had unexpected: " + e.getValue()); + } + assertTrue("There are no unhandelled exceptions, see: log for detail on: " + unhandeledExceptions, + unhandeledExceptions.isEmpty()); + } + + public NetworkConnector bridge(String from, String to) throws Exception { + NetworkConnector networkConnector = bridgeBrokers(from, to, true, -1, CONDUIT); + networkConnector.setSuppressDuplicateQueueSubscriptions(true); + networkConnector.setDecreaseNetworkConsumerPriority(true); + networkConnector.setConsumerTTL(1); + networkConnector.setDuplex(duplex); + return networkConnector; + } + + public static Test suite() { + return suite(AMQ4607Test.class); + } + + public void initCombos() { + addCombinationValues("duplex", new Boolean[]{Boolean.TRUE, Boolean.FALSE}); + } + + public void testMigratingConsumer() throws Exception { + bridge("Broker0", "Broker1"); + if (!duplex) bridge("Broker1", "Broker0"); + + bridge("Broker1", "Broker2"); + if (!duplex) bridge("Broker2", "Broker1"); + + bridge("Broker0", "Broker2"); + if (!duplex) bridge("Broker2", "Broker0"); + + startAllBrokers(); + this.waitForBridgeFormation(); + + Destination dest = createDestination("TEST.FOO", false); + sendMessages("Broker0", dest, 1); + + for (int i=0; i< BROKER_COUNT; i++) { + MessageConsumer messageConsumer = createConsumer("Broker" + i, dest, "DoNotConsume = 'true'"); + + for (int J = 0; J < BROKER_COUNT; J++) { + assertExactConsumersConnect("Broker" + J, dest, CONSUMER_COUNT, TIMEOUT); + } + + assertNoUnhandeledExceptions(); + + assertExactMessageCount("Broker" + i, dest, 1, TIMEOUT); + + messageConsumer.close(); + LOG.info("Check for no consumers.."); + for (int J = 0; J < BROKER_COUNT; J++) { + assertExactConsumersConnect("Broker" + J, dest, 0, TIMEOUT); + } + } + + // now consume the message + final String brokerId = "Broker2"; + MessageConsumer messageConsumer = createConsumer(brokerId, dest); + assertTrue("Consumed ok", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return brokers.get(brokerId).allMessages.getMessageIds().size() == 1; + } + })); + messageConsumer.close(); + + } + + public void testMigratingConsumerFullCircle() throws Exception { + bridge("Broker0", "Broker1"); + if (!duplex) bridge("Broker1", "Broker0"); + + bridge("Broker1", "Broker2"); + if (!duplex) bridge("Broker2", "Broker1"); + + bridge("Broker0", "Broker2"); + if (!duplex) bridge("Broker2", "Broker0"); + + // allow full loop, immediate replay back to 0 from 2 + ConditionalNetworkBridgeFilterFactory conditionalNetworkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); + conditionalNetworkBridgeFilterFactory.setReplayDelay(0); + conditionalNetworkBridgeFilterFactory.setReplayWhenNoConsumers(true); + brokers.get("Broker2").broker.getDestinationPolicy().getDefaultEntry().setNetworkBridgeFilterFactory(conditionalNetworkBridgeFilterFactory); + startAllBrokers(); + this.waitForBridgeFormation(); + + Destination dest = createDestination("TEST.FOO", false); + + sendMessages("Broker0", dest, 1); + + for (int i=0; i< BROKER_COUNT; i++) { + MessageConsumer messageConsumer = createConsumer("Broker" + i, dest, "DoNotConsume = 'true'"); + + for (int J = 0; J < BROKER_COUNT; J++) { + assertExactConsumersConnect("Broker" + J, dest, CONSUMER_COUNT, TIMEOUT); + } + + assertNoUnhandeledExceptions(); + + // validate the message has been forwarded + assertExactMessageCount("Broker" + i, dest, 1, TIMEOUT); + + messageConsumer.close(); + LOG.info("Check for no consumers.."); + for (int J = 0; J < BROKER_COUNT; J++) { + assertExactConsumersConnect("Broker" + J, dest, 0, TIMEOUT); + } + } + + // now consume the message from the origin + LOG.info("Consume from origin..."); + final String brokerId = "Broker0"; + MessageConsumer messageConsumer = createConsumer(brokerId, dest); + assertTrue("Consumed ok", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return brokers.get(brokerId).allMessages.getMessageIds().size() == 1; + } + })); + messageConsumer.close(); + + } + + protected void assertExactMessageCount(final String brokerName, Destination destination, final int count, long timeout) throws Exception { + ManagementContext context = brokers.get(brokerName).broker.getManagementContext(); + final QueueViewMBean queueViewMBean = (QueueViewMBean) context.newProxyInstance(brokers.get(brokerName).broker.getAdminView().getQueues()[0], QueueViewMBean.class, false); + assertTrue("Excepected queue depth: " + count + " on: " + brokerName, Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + long currentCount = queueViewMBean.getQueueSize(); + LOG.info("On " + brokerName + " current queue size for " + queueViewMBean + ", " + currentCount); + if (count != currentCount) { + LOG.info("Sub IDs: " + Arrays.asList(queueViewMBean.getSubscriptions())); + } + return currentCount == count; + } + }, timeout)); + } + + protected void assertExactConsumersConnect(final String brokerName, Destination destination, final int count, long timeout) throws Exception { + final ManagementContext context = brokers.get(brokerName).broker.getManagementContext(); + assertTrue("Excepected consumers count: " + count + " on: " + brokerName, Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + try { + QueueViewMBean queueViewMBean = (QueueViewMBean) context.newProxyInstance(brokers.get(brokerName).broker.getAdminView().getQueues()[0], QueueViewMBean.class, false); + long currentCount = queueViewMBean.getConsumerCount(); + LOG.info("On " + brokerName + " current consumer count for " + queueViewMBean + ", " + currentCount); + if (count != currentCount) { + LOG.info("Sub IDs: " + Arrays.asList(queueViewMBean.getSubscriptions())); + } + return currentCount == count; + } catch (Exception e) { + LOG.warn("Unexpected: " + e, e); + return false; + } + } + }, timeout)); + } + + public void setUp() throws Exception { + super.setUp(); + + unhandeledExceptions.clear(); + Thread.setDefaultUncaughtExceptionHandler(this); + + // Setup n brokers + for (int i = 0; i < BROKER_COUNT; i++) { + createBroker(new URI("broker:(tcp://localhost:6161" + i + ")/Broker" + i + "?persistent=false&useJmx=true")); + } + + consumerMap = new LinkedHashMap(); + } + + @Override + protected void configureBroker(BrokerService brokerService) { + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setExpireMessagesPeriod(0); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(policyEntry); + brokerService.setDestinationPolicy(policyMap); + } + + public void uncaughtException(Thread t, Throwable e) { + synchronized(unhandeledExceptions) { + unhandeledExceptions.put(t,e); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4636Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4636Test.java new file mode 100644 index 0000000000..014d86a525 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4636Test.java @@ -0,0 +1,267 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.concurrent.CountDownLatch; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.store.jdbc.DataSourceServiceSupport; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.jdbc.LeaseDatabaseLocker; +import org.apache.activemq.store.jdbc.TransactionContext; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.LeaseLockerIOExceptionHandler; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.junit.Assert.fail; + +/** + * Testing how the broker reacts when a SQL Exception is thrown from + * org.apache.activemq.store.jdbc.TransactionContext.executeBatch(). + *

+ * see https://issues.apache.org/jira/browse/AMQ-4636 + */ +public class AMQ4636Test { + + private static final String MY_TEST_TOPIC = "MY_TEST_TOPIC"; + private static final Logger LOG = LoggerFactory + .getLogger(AMQ4636Test.class); + private String transportUrl = "tcp://0.0.0.0:0"; + private BrokerService broker; + EmbeddedDataSource embeddedDataSource; + CountDownLatch throwSQLException = new CountDownLatch(0); + + @Before + public void startBroker() throws Exception { + broker = createBroker(); + broker.deleteAllMessages(); + broker.start(); + broker.waitUntilStarted(); + LOG.info("Broker started..."); + } + + @After + public void stopBroker() throws Exception { + if (broker != null) { + LOG.info("Stopping broker..."); + broker.stop(); + broker.waitUntilStopped(); + } + try { + if (embeddedDataSource != null) { + // ref http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBCDataSource.java?view=markup + embeddedDataSource.setShutdownDatabase("shutdown"); + embeddedDataSource.getConnection(); + } + } catch (Exception ignored) { + } finally { + embeddedDataSource.setShutdownDatabase(null); + } + } + + protected BrokerService createBroker() throws Exception { + + embeddedDataSource = (EmbeddedDataSource) DataSourceServiceSupport.createDataSource(IOHelper.getDefaultDataDirectory()); + embeddedDataSource.setCreateDatabase("create"); + embeddedDataSource.getConnection().close(); + + //wire in a TestTransactionContext (wrapper to TransactionContext) that has an executeBatch() + // method that can be configured to throw a SQL exception on demand + JDBCPersistenceAdapter jdbc = new TestJDBCPersistenceAdapter(); + jdbc.setDataSource(embeddedDataSource); + + jdbc.setLockKeepAlivePeriod(1000l); + LeaseDatabaseLocker leaseDatabaseLocker = new LeaseDatabaseLocker(); + leaseDatabaseLocker.setLockAcquireSleepInterval(2000l); + jdbc.setLocker(leaseDatabaseLocker); + + broker = new BrokerService(); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setExpireMessagesPeriod(0); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + broker.setPersistenceAdapter(jdbc); + + broker.setIoExceptionHandler(new LeaseLockerIOExceptionHandler()); + + transportUrl = broker.addConnector(transportUrl).getPublishableConnectString(); + return broker; + } + + /** + * adding a TestTransactionContext (wrapper to TransactionContext) so an SQLException is triggered + * during TransactionContext.executeBatch() when called in the broker. + *

+ * Expectation: SQLException triggers a connection shutdown and failover should kick and try to redeliver the + * message. SQLException should NOT be returned to client + */ + @Test + public void testProducerWithDBShutdown() throws Exception { + + // failover but timeout in 1 seconds so the test does not hang + String failoverTransportURL = "failover:(" + transportUrl + + ")?timeout=1000"; + + this.createDurableConsumer(MY_TEST_TOPIC, failoverTransportURL); + + this.sendMessage(MY_TEST_TOPIC, failoverTransportURL, false, false); + + } + + @Test + public void testTransactedProducerCommitWithDBShutdown() throws Exception { + + // failover but timeout in 1 seconds so the test does not hang + String failoverTransportURL = "failover:(" + transportUrl + + ")?timeout=1000"; + + this.createDurableConsumer(MY_TEST_TOPIC, failoverTransportURL); + + try { + this.sendMessage(MY_TEST_TOPIC, failoverTransportURL, true, true); + fail("Expect rollback after failover - inddoubt commit"); + } catch (javax.jms.TransactionRolledBackException expectedInDoubt) { + LOG.info("Got rollback after failover failed commit", expectedInDoubt); + } + } + + @Test + public void testTransactedProducerRollbackWithDBShutdown() throws Exception { + + // failover but timeout in 1 seconds so the test does not hang + String failoverTransportURL = "failover:(" + transportUrl + + ")?timeout=1000"; + + this.createDurableConsumer(MY_TEST_TOPIC, failoverTransportURL); + + this.sendMessage(MY_TEST_TOPIC, failoverTransportURL, true, false); + } + + public void createDurableConsumer(String topic, + String transportURL) throws JMSException { + Connection connection = null; + LOG.info("*** createDurableConsumer() called ..."); + + try { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + transportURL); + + connection = factory.createConnection(); + connection.setClientID("myconn1"); + Session session = connection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTopic(topic); + + TopicSubscriber topicSubscriber = session.createDurableSubscriber( + (Topic) destination, "MySub1"); + } finally { + if (connection != null) { + connection.close(); + } + } + } + + public void sendMessage(String topic, String transportURL, boolean transacted, boolean commit) + throws JMSException { + Connection connection = null; + + try { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + transportURL); + + connection = factory.createConnection(); + Session session = connection.createSession(transacted, + transacted ? Session.SESSION_TRANSACTED : Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTopic(topic); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + Message m = session.createTextMessage("testMessage"); + LOG.info("*** send message to broker..."); + + // trigger SQL exception in transactionContext + throwSQLException = new CountDownLatch(1); + producer.send(m); + + if (transacted) { + if (commit) { + session.commit(); + } else { + session.rollback(); + } + } + + LOG.info("*** Finished send message to broker"); + + } finally { + if (connection != null) { + connection.close(); + } + } + } + + /* + * Mock classes used for testing + */ + + public class TestJDBCPersistenceAdapter extends JDBCPersistenceAdapter { + + public TransactionContext getTransactionContext() throws IOException { + return new TestTransactionContext(this); + } + } + + public class TestTransactionContext extends TransactionContext { + + public TestTransactionContext( + JDBCPersistenceAdapter jdbcPersistenceAdapter) + throws IOException { + super(jdbcPersistenceAdapter); + } + + @Override + public void executeBatch() throws SQLException { + if (throwSQLException.getCount() > 0) { + // only throw exception once + throwSQLException.countDown(); + throw new SQLException("TEST SQL EXCEPTION"); + } + super.executeBatch(); + } + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4656Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4656Test.java new file mode 100644 index 0000000000..fcdf23edd8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4656Test.java @@ -0,0 +1,153 @@ +/** + * 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.bugs; + +import java.util.Arrays; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerView; +import org.apache.activemq.broker.jmx.DurableSubscriptionViewMBean; +import org.apache.activemq.broker.region.policy.FilePendingDurableSubscriberMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PendingDurableSubscriberMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.StorePendingDurableSubscriberMessageStoragePolicy; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class AMQ4656Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ4656Test.class); + private static BrokerService brokerService; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + + private String connectionUri; + + @Parameterized.Parameter + public PendingDurableSubscriberMessageStoragePolicy pendingDurableSubPolicy; + + @Parameterized.Parameters(name="{0}") + public static Iterable getTestParameters() { + return Arrays.asList(new Object[][]{{new FilePendingDurableSubscriberMessageStoragePolicy()},{new StorePendingDurableSubscriberMessageStoragePolicy()}}); + } + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setPendingDurableSubscriberPolicy(pendingDurableSubPolicy); + policyMap.setDefaultEntry(defaultEntry); + brokerService.setDestinationPolicy(policyMap); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + brokerService.setDeleteAllMessagesOnStartup(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + brokerService.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testDurableConsumerEnqueueCountWithZeroPrefetch() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionUri); + + Connection connection = connectionFactory.createConnection(); + connection.setClientID(getClass().getName()); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTopic("DurableTopic"); + + MessageConsumer consumer = session.createDurableSubscriber((Topic) destination, "EnqueueSub"); + + BrokerView view = brokerService.getAdminView(); + view.getDurableTopicSubscribers(); + + ObjectName subName = view.getDurableTopicSubscribers()[0]; + + DurableSubscriptionViewMBean sub = (DurableSubscriptionViewMBean) + brokerService.getManagementContext().newProxyInstance(subName, DurableSubscriptionViewMBean.class, true); + + assertEquals(0, sub.getEnqueueCounter()); + assertEquals(0, sub.getDequeueCounter()); + assertEquals(0, sub.getPendingQueueSize()); + assertEquals(0, sub.getDispatchedCounter()); + assertEquals(0, sub.getDispatchedQueueSize()); + + consumer.close(); + + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < 20; i++) { + producer.send(session.createMessage()); + } + producer.close(); + + consumer = session.createDurableSubscriber((Topic) destination, "EnqueueSub"); + + Thread.sleep(1000); + + assertEquals(20, sub.getEnqueueCounter()); + assertEquals(0, sub.getDequeueCounter()); + assertEquals(0, sub.getPendingQueueSize()); + assertEquals(20, sub.getDispatchedCounter()); + assertEquals(20, sub.getDispatchedQueueSize()); + + LOG.info("Pending Queue Size with no receives: {}", sub.getPendingQueueSize()); + + assertNotNull(consumer.receive(1000)); + assertNotNull(consumer.receive(1000)); + + consumer.close(); + + Thread.sleep(2000); + + LOG.info("Pending Queue Size with two receives: {}", sub.getPendingQueueSize()); + + assertEquals(20, sub.getEnqueueCounter()); + assertEquals(2, sub.getDequeueCounter()); + assertEquals(18, sub.getPendingQueueSize()); + assertEquals(20, sub.getDispatchedCounter()); + assertEquals(0, sub.getDispatchedQueueSize()); + + session.close(); + connection.close(); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4671Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4671Test.java new file mode 100644 index 0000000000..b69ab4716e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4671Test.java @@ -0,0 +1,81 @@ +/** + * 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.bugs; + +import static org.junit.Assert.fail; + +import javax.jms.Connection; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4671Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ4671Test.class); + private static BrokerService brokerService; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + + private String connectionUri; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + brokerService.setDeleteAllMessagesOnStartup(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + connectionUri = connectionUri + "?trace=true"; + brokerService.start(); + brokerService.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testNonDurableSubscriberInvalidUnsubscribe() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionUri); + + Connection connection = connectionFactory.createConnection(); + connection.setClientID(getClass().getName()); + connection.start(); + + try { + Session ts = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + try { + ts.unsubscribe("invalid-subscription-name"); + fail("this should fail"); + } catch (javax.jms.InvalidDestinationException e) { + LOG.info("Test caught correct invalid destination exception"); + } + } finally { + if (connection != null) { + connection.close(); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4677Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4677Test.java new file mode 100644 index 0000000000..fd80690f07 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4677Test.java @@ -0,0 +1,184 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.*; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.leveldb.LevelDBStoreViewMBean; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4677Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ4677Test.class); + private static BrokerService brokerService; + + @Rule public TestName name = new TestName(); + + private File dataDirFile; + + @Before + public void setUp() throws Exception { + + dataDirFile = new File("target/LevelDBCleanupTest"); + + brokerService = new BrokerService(); + brokerService.setBrokerName("LevelDBBroker"); + brokerService.setPersistent(true); + brokerService.setUseJmx(true); + brokerService.setAdvisorySupport(false); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setDataDirectoryFile(dataDirFile); + + LevelDBStore persistenceFactory = new LevelDBStore(); + persistenceFactory.setDirectory(dataDirFile); + brokerService.setPersistenceAdapter(persistenceFactory); + brokerService.start(); + brokerService.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testSendAndReceiveAllMessages() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://LevelDBBroker"); + + Connection connection = connectionFactory.createConnection(); + connection.setClientID(getClass().getName()); + connection.start(); + + final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(name.toString()); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + final LevelDBStoreViewMBean levelDBView = getLevelDBStoreMBean(); + assertNotNull(levelDBView); + levelDBView.compact(); + + final int SIZE = 6 * 1024 * 5; + final int MSG_COUNT = 60000; + final CountDownLatch done = new CountDownLatch(MSG_COUNT); + + byte buffer[] = new byte[SIZE]; + for (int i = 0; i < SIZE; ++i) { + buffer[i] = (byte) 128; + } + + for (int i = 0; i < MSG_COUNT; ++i) { + BytesMessage message = session.createBytesMessage(); + message.writeBytes(buffer); + producer.send(message); + + if ((i % 1000) == 0) { + LOG.info("Sent message #{}", i); + session.commit(); + } + } + + session.commit(); + + LOG.info("Finished sending all messages."); + + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + if ((done.getCount() % 1000) == 0) { + try { + LOG.info("Received message #{}", MSG_COUNT - done.getCount()); + session.commit(); + } catch (JMSException e) { + } + } + done.countDown(); + } + }); + + done.await(15, TimeUnit.MINUTES); + session.commit(); + LOG.info("Finished receiving all messages."); + + assertTrue("Should < 3 logfiles left.", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + levelDBView.compact(); + return countLogFiles() < 3; + } + }, TimeUnit.MINUTES.toMillis(5), (int)TimeUnit.SECONDS.toMillis(30))); + + levelDBView.compact(); + LOG.info("Current number of logs {}", countLogFiles()); + } + + protected long countLogFiles() { + String[] logFiles = dataDirFile.list(new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + if (name.endsWith("log")) { + return true; + } + return false; + } + }); + + LOG.info("Current number of logs {}", logFiles.length); + return logFiles.length; + } + + protected LevelDBStoreViewMBean getLevelDBStoreMBean() throws Exception { + ObjectName levelDbViewMBeanQuery = new ObjectName( + "org.apache.activemq:type=Broker,brokerName=LevelDBBroker,service=PersistenceAdapter,instanceName=LevelDB*"); + + Set names = brokerService.getManagementContext().queryNames(null, levelDbViewMBeanQuery); + if (names.isEmpty() || names.size() > 1) { + throw new java.lang.IllegalStateException("Can't find levelDB store name."); + } + + LevelDBStoreViewMBean proxy = (LevelDBStoreViewMBean) brokerService.getManagementContext() + .newProxyInstance(names.iterator().next(), LevelDBStoreViewMBean.class, true); + return proxy; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4853Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4853Test.java new file mode 100644 index 0000000000..a3472792ee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4853Test.java @@ -0,0 +1,300 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisoryBroker; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.SessionId; +import org.apache.activemq.command.SessionInfo; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4853Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ4853Test.class); + private static BrokerService brokerService; + private static final String BROKER_ADDRESS = "tcp://localhost:0"; + private static final ActiveMQQueue DESTINATION = new ActiveMQQueue("TEST.QUEUE"); + private CountDownLatch cycleDoneLatch; + + private String connectionUri; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(false); + brokerService.setAdvisorySupport(true); + brokerService.setDeleteAllMessagesOnStartup(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + + brokerService.start(); + brokerService.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + /** + * Test to shows the performance of the removing consumers while other stay active. + * @throws Exception + */ + @Ignore + @Test + public void test() throws Exception { + + // Create a stable set of consumers to fill in the advisory broker's consumer list. + ArrayList fixedConsumers = new ArrayList(100); + for (int i = 0; i < 200; ++i) { + fixedConsumers.add(new Consumer()); + } + + // Create a set of consumers that comes online for a short time and then + // goes offline again. Cycles will repeat as each batch completes + final int fixedDelayConsumers = 300; + final int fixedDelayCycles = 25; + + final CountDownLatch fixedDelayCycleLatch = new CountDownLatch(fixedDelayCycles); + + // Update so done method can track state. + cycleDoneLatch = fixedDelayCycleLatch; + + CyclicBarrier barrier = new CyclicBarrier(fixedDelayConsumers, new Runnable() { + @Override + public void run() { + LOG.info("Fixed delay consumers cycle {} completed.", fixedDelayCycleLatch.getCount()); + fixedDelayCycleLatch.countDown(); + } + }); + + for (int i = 0; i < fixedDelayConsumers; ++i) { + new Thread(new FixedDelyConsumer(barrier)).start(); + } + + fixedDelayCycleLatch.await(10, TimeUnit.MINUTES); + + // Clean up. + + for (Consumer consumer : fixedConsumers) { + consumer.close(); + } + fixedConsumers.clear(); + } + + private ConnectionInfo createConnectionInfo() { + ConnectionId id = new ConnectionId(); + id.setValue("ID:123456789:0:1"); + + ConnectionInfo info = new ConnectionInfo(); + info.setConnectionId(id); + return info; + } + + private SessionInfo createSessionInfo(ConnectionInfo connection) { + SessionId id = new SessionId(connection.getConnectionId(), 1); + + SessionInfo info = new SessionInfo(); + info.setSessionId(id); + + return info; + } + + public ConsumerInfo createConsumerInfo(SessionInfo session, int value, ActiveMQDestination destination) { + ConsumerId id = new ConsumerId(); + id.setConnectionId(session.getSessionId().getConnectionId()); + id.setSessionId(1); + id.setValue(value); + + ConsumerInfo info = new ConsumerInfo(); + info.setConsumerId(id); + info.setDestination(destination); + return info; + } + + /** + * Test to shows the performance impact of removing consumers in various scenarios. + * @throws Exception + */ + @Ignore + @Test + public void testPerformanceOfRemovals() throws Exception { + // setup + AdvisoryBroker testObj = (AdvisoryBroker) brokerService.getBroker().getAdaptor(AdvisoryBroker.class); + ActiveMQDestination destination = new ActiveMQQueue("foo"); + ConnectionInfo connectionInfo = createConnectionInfo(); + ConnectionContext connectionContext = new ConnectionContext(connectionInfo); + connectionContext.setBroker(brokerService.getBroker()); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + + long start = System.currentTimeMillis(); + + for (int i = 0; i < 200; ++i) { + + for (int j = 1; j <= 500; j++) { + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, j, destination); + testObj.addConsumer(connectionContext, consumerInfo); + } + + for (int j = 500; j > 0; j--) { + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, j, destination); + testObj.removeConsumer(connectionContext, consumerInfo); + } + + for (int j = 1; j <= 500; j++) { + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, j, destination); + testObj.addConsumer(connectionContext, consumerInfo); + } + + for (int j = 1; j <= 500; j++) { + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, j, destination); + testObj.removeConsumer(connectionContext, consumerInfo); + } + } + + long finish = System.currentTimeMillis(); + + long totalTime = finish - start; + + LOG.info("Total test time: {} seconds", TimeUnit.MILLISECONDS.toSeconds(totalTime)); + + assertEquals(0, testObj.getAdvisoryConsumers().size()); + } + + @Test + public void testEqualsNeeded() throws Exception { + // setup + AdvisoryBroker testObj = (AdvisoryBroker) brokerService.getBroker().getAdaptor(AdvisoryBroker.class); + ActiveMQDestination destination = new ActiveMQQueue("foo"); + ConnectionInfo connectionInfo = createConnectionInfo(); + ConnectionContext connectionContext = new ConnectionContext(connectionInfo); + connectionContext.setBroker(brokerService.getBroker()); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + + for (int j = 1; j <= 5; j++) { + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, j, destination); + testObj.addConsumer(connectionContext, consumerInfo); + } + + for (int j = 1; j <= 5; j++) { + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, j, destination); + testObj.removeConsumer(connectionContext, consumerInfo); + } + + assertEquals(0, testObj.getAdvisoryConsumers().size()); + } + + private boolean done() { + if (cycleDoneLatch == null) { + return true; + } + return cycleDoneLatch.getCount() == 0; + } + + class Consumer implements MessageListener { + + Connection connection; + Session session; + Destination destination; + MessageConsumer consumer; + + Consumer() throws JMSException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(DESTINATION); + consumer.setMessageListener(this); + connection.start(); + } + + @Override + public void onMessage(Message message) { + } + + public void close() { + try { + connection.close(); + } catch(Exception e) { + } + + connection = null; + session = null; + consumer = null; + } + } + + class FixedDelyConsumer implements Runnable { + + private final CyclicBarrier barrier; + private final int sleepInterval; + + public FixedDelyConsumer(CyclicBarrier barrier) { + this.barrier = barrier; + this.sleepInterval = 1000; + } + + public FixedDelyConsumer(CyclicBarrier barrier, int sleepInterval) { + this.barrier = barrier; + this.sleepInterval = sleepInterval; + } + + @Override + public void run() { + while (!done()) { + + try { + Consumer consumer = new Consumer(); + TimeUnit.MILLISECONDS.sleep(sleepInterval); + consumer.close(); + barrier.await(); + } catch (Exception ex) { + return; + } + } + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4887Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4887Test.java new file mode 100644 index 0000000000..cf33ecec70 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4887Test.java @@ -0,0 +1,165 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.StreamMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4887Test { + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ4887Test.class); + private static final Integer ITERATIONS = 10; + + @Rule + public TestName name = new TestName(); + + @Test + public void testBytesMessageSetPropertyBeforeCopy() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + doTestBytesMessageSetPropertyBeforeCopy(connection); + } + + @Test + public void testBytesMessageSetPropertyBeforeCopyCompressed() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + connectionFactory.setUseCompression(true); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + doTestBytesMessageSetPropertyBeforeCopy(connection); + } + + public void doTestBytesMessageSetPropertyBeforeCopy(Connection connection) throws Exception { + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(name.toString()); + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(destination); + + BytesMessage message = session.createBytesMessage(); + + for (int i=0; i < ITERATIONS; i++) { + + long sendTime = System.currentTimeMillis(); + message.setLongProperty("sendTime", sendTime); + producer.send(message); + + LOG.debug("Receiving message " + i); + Message receivedMessage = consumer.receive(5000); + assertNotNull("On message " + i, receivedMessage); + assertTrue("On message " + i, receivedMessage instanceof BytesMessage); + + BytesMessage receivedBytesMessage = (BytesMessage) receivedMessage; + + int numElements = 0; + try { + while (true) { + receivedBytesMessage.readBoolean(); + numElements++; + } + } catch (Exception ex) { + } + + LOG.info("Iteration [{}]: Received Message contained {} boolean values.", i, numElements); + assertEquals(i, numElements); + + long receivedSendTime = receivedBytesMessage.getLongProperty("sendTime"); + assertEquals("On message " + i, receivedSendTime, sendTime); + + // Add a new bool value on each iteration. + message.writeBoolean(true); + } + } + + @Test + public void testStreamMessageSetPropertyBeforeCopy() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + doTestStreamMessageSetPropertyBeforeCopy(connection); + } + + @Test + public void testStreamMessageSetPropertyBeforeCopyCompressed() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + connectionFactory.setUseCompression(true); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.start(); + doTestStreamMessageSetPropertyBeforeCopy(connection); + } + + public void doTestStreamMessageSetPropertyBeforeCopy(Connection connection) throws Exception { + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(name.toString()); + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer = session.createProducer(destination); + + StreamMessage message = session.createStreamMessage(); + + for (int i=0; i < ITERATIONS; i++) { + + long sendTime = System.currentTimeMillis(); + message.setLongProperty("sendTime", sendTime); + producer.send(message); + + LOG.debug("Receiving message " + i); + Message receivedMessage = consumer.receive(5000); + assertNotNull("On message " + i, receivedMessage); + assertTrue("On message " + i, receivedMessage instanceof StreamMessage); + + StreamMessage receivedStreamMessage = (StreamMessage) receivedMessage; + + int numElements = 0; + try { + while (true) { + receivedStreamMessage.readBoolean(); + numElements++; + } + } catch (Exception ex) { + } + + LOG.info("Iteration [{}]: Received Message contained {} boolean values.", i, numElements); + assertEquals(i, numElements); + + long receivedSendTime = receivedStreamMessage.getLongProperty("sendTime"); + assertEquals("On message " + i, receivedSendTime, sendTime); + + // Add a new bool value on each iteration. + message.writeBoolean(true); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4893Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4893Test.java new file mode 100644 index 0000000000..026a4be42d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4893Test.java @@ -0,0 +1,86 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.util.Map; + +import javax.jms.JMSException; + +import org.apache.activemq.command.ActiveMQObjectMessage; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.util.ByteSequence; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4893Test { + + private static final transient Logger LOG = LoggerFactory.getLogger(AMQ4893Test.class); + + @Test + public void testPropertiesInt() throws Exception { + ActiveMQObjectMessage message = new ActiveMQObjectMessage(); + message.setIntProperty("TestProp", 333); + fakeUnmarshal(message); + roundTripProperties(message); + } + + @Test + public void testPropertiesString() throws Exception { + ActiveMQObjectMessage message = new ActiveMQObjectMessage(); + message.setStringProperty("TestProp", "Value"); + fakeUnmarshal(message); + roundTripProperties(message); + } + + @Test + public void testPropertiesObject() throws Exception { + ActiveMQObjectMessage message = new ActiveMQObjectMessage(); + message.setObjectProperty("TestProp", "Value"); + fakeUnmarshal(message); + roundTripProperties(message); + } + + @Test + public void testPropertiesObjectNoMarshalling() throws Exception { + ActiveMQObjectMessage message = new ActiveMQObjectMessage(); + message.setObjectProperty("TestProp", "Value"); + roundTripProperties(message); + } + + private void roundTripProperties(ActiveMQObjectMessage message) throws IOException, JMSException { + ActiveMQObjectMessage copy = new ActiveMQObjectMessage(); + for (Map.Entry prop : message.getProperties().entrySet()) { + LOG.debug("{} -> {}", prop.getKey(), prop.getValue().getClass()); + copy.setObjectProperty(prop.getKey(), prop.getValue()); + } + } + + private void fakeUnmarshal(ActiveMQObjectMessage message) throws IOException { + // we need to force the unmarshalled property field to be set so it + // gives us a hawtbuffer for the string + OpenWireFormat format = new OpenWireFormat(); + message.beforeMarshall(format); + message.afterMarshall(format); + + ByteSequence seq = message.getMarshalledProperties(); + message.clearProperties(); + message.setMarshalledProperties(seq); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4899Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4899Test.java new file mode 100644 index 0000000000..81140ce8e8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4899Test.java @@ -0,0 +1,192 @@ +/** + * 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.bugs; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.plugin.SubQueueSelectorCacheBrokerPlugin; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; + +public class AMQ4899Test { + protected static final Logger LOG = LoggerFactory.getLogger(AMQ4899Test.class); + private static final String QUEUE_NAME="AMQ4899TestQueue"; + private static final String CONSUMER_QUEUE="Consumer.Orders.VirtualOrders." + QUEUE_NAME; + private static final String PRODUCER_DESTINATION_NAME = "VirtualOrders." + QUEUE_NAME; + + private static final Integer MESSAGE_LIMIT = 20; + public static final String CONSUMER_A_SELECTOR = "Order < " + 10; + public static String CONSUMER_B_SELECTOR = "Order >= " + 10; + private CountDownLatch consumersStarted = new CountDownLatch(2); + private CountDownLatch consumerAtoConsumeCount= new CountDownLatch(10); + private CountDownLatch consumerBtoConsumeCount = new CountDownLatch(10); + + private BrokerService broker; + + @Before + public void setUp() { + setupBroker("broker://()/localhost?"); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test(timeout = 60 * 1000) + public void testVirtualTopicMultipleSelectors() throws Exception{ + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue consumerQueue = session.createQueue(CONSUMER_QUEUE); + + MessageListener listenerA = new AMQ4899Listener("A", consumersStarted, consumerAtoConsumeCount); + MessageConsumer consumerA = session.createConsumer(consumerQueue, CONSUMER_A_SELECTOR); + consumerA.setMessageListener(listenerA); + + MessageListener listenerB = new AMQ4899Listener("B", consumersStarted, consumerBtoConsumeCount); + MessageConsumer consumerB = session.createConsumer(consumerQueue, CONSUMER_B_SELECTOR); + consumerB.setMessageListener(listenerB); + + consumersStarted.await(10, TimeUnit.SECONDS); + assertEquals("Not all consumers started in time", 0, consumersStarted.getCount()); + + Destination producerDestination = session.createTopic(PRODUCER_DESTINATION_NAME); + MessageProducer producer = session.createProducer(producerDestination); + int messageIndex = 0; + for (int i=0; i < MESSAGE_LIMIT; i++) { + if (i==3) { + LOG.debug("Stopping consumerA"); + consumerA.close(); + } + + if (i == 14) { + LOG.debug("Stopping consumer B"); + consumerB.close(); + } + String messageText = "hello " + messageIndex++ + " sent at " + new java.util.Date().toString(); + TextMessage message = session.createTextMessage(messageText); + message.setIntProperty("Order", i); + LOG.debug("Sending message [{}]", messageText); + producer.send(message); + Thread.sleep(100); + } + Thread.sleep(1 * 1000); + + // restart consumerA + LOG.debug("Restarting consumerA"); + consumerA = session.createConsumer(consumerQueue, CONSUMER_A_SELECTOR); + consumerA.setMessageListener(listenerA); + + // restart consumerB + LOG.debug("restarting consumerB"); + consumerB = session.createConsumer(consumerQueue, CONSUMER_B_SELECTOR); + consumerB.setMessageListener(listenerB); + + consumerAtoConsumeCount.await(5, TimeUnit.SECONDS); + consumerBtoConsumeCount.await(5, TimeUnit.SECONDS); + + LOG.debug("Unconsumed messages for consumerA {} consumerB {}", consumerAtoConsumeCount.getCount(), consumerBtoConsumeCount.getCount()); + + assertEquals("Consumer A did not consume all messages", 0, consumerAtoConsumeCount.getCount()); + assertEquals("Consumer B did not consume all messages", 0, consumerBtoConsumeCount.getCount()); + + connection.close(); + } + + /** + * Setup broker with VirtualTopic configured + */ + private void setupBroker(String uri) { + try { + broker = BrokerFactory.createBroker(uri); + + VirtualDestinationInterceptor interceptor = new VirtualDestinationInterceptor(); + VirtualTopic virtualTopic = new VirtualTopic(); + virtualTopic.setName("VirtualOrders.>"); + virtualTopic.setSelectorAware(true); + VirtualDestination[] virtualDestinations = { virtualTopic }; + interceptor.setVirtualDestinations(virtualDestinations); + broker.setDestinationInterceptors(new DestinationInterceptor[]{interceptor}); + + SubQueueSelectorCacheBrokerPlugin subQueueSelectorCacheBrokerPlugin = new SubQueueSelectorCacheBrokerPlugin(); + BrokerPlugin[] updatedPlugins = {subQueueSelectorCacheBrokerPlugin}; + broker.setPlugins(updatedPlugins); + + broker.start(); + broker.waitUntilStarted(); + } catch (Exception e) { + LOG.error("Failed creating broker", e); + } + } +} + +class AMQ4899Listener implements MessageListener { + Logger LOG = LoggerFactory.getLogger(AMQ4899Listener.class); + CountDownLatch toConsume; + String id; + + public AMQ4899Listener(String id, CountDownLatch started, CountDownLatch toConsume) { + this.id = id; + this.toConsume = toConsume; + started.countDown(); + } + + @Override + public void onMessage(Message message) { + toConsume.countDown(); + try { + if (message instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message; + LOG.debug("Listener {} received [{}]", id, textMessage.getText()); + } else { + LOG.error("Listener {} Expected a TextMessage, got {}", id, message.getClass().getCanonicalName()); + } + } catch (JMSException e) { + LOG.error("Unexpected JMSException in Listener " + id, e); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4930Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4930Test.java new file mode 100644 index 0000000000..e65ad91f14 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4930Test.java @@ -0,0 +1,144 @@ +/** + * 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.bugs; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ4930Test extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(AMQ4930Test.class); + final int messageCount = 150; + final int messageSize = 1024*1024; + final int maxBrowsePageSize = 50; + final ActiveMQQueue bigQueue = new ActiveMQQueue("BIG"); + BrokerService broker; + ActiveMQConnectionFactory factory; + + protected void configureBroker() throws Exception { + broker.setDeleteAllMessagesOnStartup(true); + broker.setAdvisorySupport(false); + broker.getSystemUsage().getMemoryUsage().setLimit(1*1024*1024); + + PolicyMap pMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + // disable expriy processing as this will call browse in parallel + policy.setExpireMessagesPeriod(0); + policy.setMaxPageSize(maxBrowsePageSize); + policy.setMaxBrowsePageSize(maxBrowsePageSize); + pMap.setDefaultEntry(policy); + + broker.setDestinationPolicy(pMap); + } + + public void testBrowsePendingNonPersistent() throws Exception { + doTestBrowsePending(DeliveryMode.NON_PERSISTENT); + } + + public void testBrowsePendingPersistent() throws Exception { + doTestBrowsePending(DeliveryMode.PERSISTENT); + } + + public void testWithStatsDisabled() throws Exception { + ((RegionBroker)broker.getRegionBroker()).getDestinationStatistics().setEnabled(false); + doTestBrowsePending(DeliveryMode.PERSISTENT); + } + + public void doTestBrowsePending(int deliveryMode) throws Exception { + + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(bigQueue); + producer.setDeliveryMode(deliveryMode); + BytesMessage bytesMessage = session.createBytesMessage(); + bytesMessage.writeBytes(new byte[messageSize]); + + for (int i = 0; i < messageCount; i++) { + producer.send(bigQueue, bytesMessage); + } + + final QueueViewMBean queueViewMBean = (QueueViewMBean) + broker.getManagementContext().newProxyInstance(broker.getAdminView().getQueues()[0], QueueViewMBean.class, false); + + LOG.info(queueViewMBean.getName() + " Size: " + queueViewMBean.getEnqueueCount()); + + connection.close(); + + assertFalse("Cache disabled on q", queueViewMBean.isCacheEnabled()); + + // ensure repeated browse does now blow mem + + final Queue underTest = (Queue) ((RegionBroker)broker.getRegionBroker()).getQueueRegion().getDestinationMap().get(bigQueue); + + // do twice to attempt to pull in 2*maxBrowsePageSize which uses up the system memory limit + Message[] browsed = underTest.browse(); + LOG.info("Browsed: " + browsed.length); + assertEquals("maxBrowsePageSize", maxBrowsePageSize, browsed.length); + browsed = underTest.browse(); + LOG.info("Browsed: " + browsed.length); + assertEquals("maxBrowsePageSize", maxBrowsePageSize, browsed.length); + Runtime.getRuntime().gc(); + long free = Runtime.getRuntime().freeMemory()/1024; + LOG.info("free at start of check: " + free); + // check for memory growth + for (int i=0; i<10; i++) { + LOG.info("free: " + Runtime.getRuntime().freeMemory()/1024); + browsed = underTest.browse(); + LOG.info("Browsed: " + browsed.length); + assertEquals("maxBrowsePageSize", maxBrowsePageSize, browsed.length); + Runtime.getRuntime().gc(); + Runtime.getRuntime().gc(); + assertTrue("No growth: " + Runtime.getRuntime().freeMemory()/1024 + " >= " + (free - (free * 0.2)), Runtime.getRuntime().freeMemory()/1024 >= (free - (free * 0.2))); + } + } + + + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + broker.setBrokerName("thisOne"); + configureBroker(); + broker.start(); + factory = new ActiveMQConnectionFactory("vm://thisOne?jms.alwaysSyncSend=true"); + factory.setWatchTopicAdvisories(false); + + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + broker = null; + } + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4950Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4950Test.java new file mode 100644 index 0000000000..acfc0f6e99 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4950Test.java @@ -0,0 +1,195 @@ +/** + * 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.bugs; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.XASession; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +import org.apache.activemq.ActiveMQXAConnection; +import org.apache.activemq.ActiveMQXAConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerRestartTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.TransactionBroker; +import org.apache.activemq.broker.TransportConnection; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.command.TransactionInfo; +import org.apache.activemq.command.XATransactionId; +import org.apache.activemq.transport.failover.FailoverTransport; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Test for AMQ-4950. + * Simulates an error during XA prepare call. + */ +public class AMQ4950Test extends BrokerRestartTestSupport { + + protected static final Logger LOG = LoggerFactory.getLogger(AMQ4950Test.class); + protected static final String simulatedExceptionMessage = "Simulating error inside tx prepare()."; + public boolean prioritySupport = false; + protected String connectionUri = null; + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + broker.setDestinationPolicy(policyMap); + broker.setDeleteAllMessagesOnStartup(true); + broker.setUseJmx(false); + connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString(); + broker.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + + @Override + public int prepareTransaction(ConnectionContext context, TransactionId xid) throws Exception { + getNext().prepareTransaction(context, xid); + LOG.debug("BrokerPlugin.prepareTransaction() will throw an exception."); + throw new XAException(simulatedExceptionMessage); + } + + @Override + public void commitTransaction(ConnectionContext context, TransactionId xid, boolean onePhase) throws Exception { + LOG.debug("BrokerPlugin.commitTransaction()."); + super.commitTransaction(context, xid, onePhase); + } + } + }); + } + + /** + * Creates XA transaction and invokes XA prepare(). + * Due to registered BrokerFilter prepare will be handled by broker + * but then throw an exception. + * Prior to fixing AMQ-4950, this resulted in a ClassCastException + * in ConnectionStateTracker.PrepareReadonlyTransactionAction.onResponse() + * causing the failover transport to reconnect and replay the XA prepare(). + */ + public void testXAPrepareFailure() throws Exception { + + assertNotNull(connectionUri); + ActiveMQXAConnectionFactory cf = new ActiveMQXAConnectionFactory("failover:(" + connectionUri + ")"); + ActiveMQXAConnection xaConnection = (ActiveMQXAConnection)cf.createConnection(); + xaConnection.start(); + XASession session = xaConnection.createXASession(); + XAResource resource = session.getXAResource(); + Xid tid = createXid(); + resource.start(tid, XAResource.TMNOFLAGS); + + MessageProducer producer = session.createProducer(session.createQueue(this.getClass().getName())); + Message message = session.createTextMessage("Sample Message"); + producer.send(message); + resource.end(tid, XAResource.TMSUCCESS); + try { + LOG.debug("Calling XA prepare(), expecting an exception"); + int ret = resource.prepare(tid); + if (XAResource.XA_OK == ret) + resource.commit(tid, false); + } catch (XAException xae) { + LOG.info("Received excpected XAException: {}", xae.getMessage()); + LOG.info("Rolling back transaction {}", tid); + + // with bug AMQ-4950 the thrown error reads "Cannot call prepare now" + // we check that we receive the original exception message as + // thrown by the BrokerPlugin + assertEquals(simulatedExceptionMessage, xae.getMessage()); + resource.rollback(tid); + } + // couple of assertions + assertTransactionGoneFromBroker(tid); + assertTransactionGoneFromConnection(broker.getBrokerName(), xaConnection.getClientID(), xaConnection.getConnectionInfo().getConnectionId(), tid); + assertTransactionGoneFromFailoverState(xaConnection, tid); + + //cleanup + producer.close(); + session.close(); + xaConnection.close(); + LOG.debug("testXAPrepareFailure() finished."); + } + + + public Xid createXid() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + os.writeLong(++txGenerator); + os.close(); + final byte[] bs = baos.toByteArray(); + + return new Xid() { + public int getFormatId() { + return 86; + } + + public byte[] getGlobalTransactionId() { + return bs; + } + + public byte[] getBranchQualifier() { + return bs; + } + }; + } + + + private void assertTransactionGoneFromFailoverState( + ActiveMQXAConnection connection1, Xid tid) throws Exception { + + FailoverTransport transport = (FailoverTransport) connection1.getTransport().narrow(FailoverTransport.class); + TransactionInfo info = new TransactionInfo(connection1.getConnectionInfo().getConnectionId(), new XATransactionId(tid), TransactionInfo.COMMIT_ONE_PHASE); + assertNull("transaction should not exist in the state tracker", + transport.getStateTracker().processCommitTransactionOnePhase(info)); + } + + + private void assertTransactionGoneFromBroker(Xid tid) throws Exception { + BrokerService broker = BrokerRegistry.getInstance().lookup("localhost"); + TransactionBroker transactionBroker = (TransactionBroker)broker.getBroker().getAdaptor(TransactionBroker.class); + try { + transactionBroker.getTransaction(null, new XATransactionId(tid), false); + fail("expected exception on tx not found"); + } catch (XAException expectedOnNotFound) { + } + } + + + private void assertTransactionGoneFromConnection(String brokerName, String clientId, ConnectionId connectionId, Xid tid) throws Exception { + BrokerService broker = BrokerRegistry.getInstance().lookup(brokerName); + CopyOnWriteArrayList connections = broker.getTransportConnectors().get(0).getConnections(); + for (TransportConnection connection: connections) { + if (connection.getConnectionId().equals(clientId)) { + try { + connection.processPrepareTransaction(new TransactionInfo(connectionId, new XATransactionId(tid), TransactionInfo.PREPARE)); + fail("did not get expected excepton on missing transaction, it must be still there in error!"); + } catch (IllegalStateException expectedOnNoTransaction) { + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4952Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4952Test.java new file mode 100644 index 0000000000..6a52e46bba --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4952Test.java @@ -0,0 +1,505 @@ +/** + * 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.bugs; + +import java.net.URI; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.sql.DataSource; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerFilter; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.network.ConditionalNetworkBridgeFilterFactory; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.Wait; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.*; + +/** + * Test creates a broker network with two brokers - producerBroker (with a + * message producer attached) and consumerBroker (with consumer attached) + *

+ * Simulates network duplicate message by stopping and restarting the + * consumerBroker after message (with message ID ending in 120) is persisted to + * consumerBrokerstore BUT BEFORE ack sent to the producerBroker over the + * network connection. When the network connection is reestablished the + * producerBroker resends message (with messageID ending in 120). + *

+ * Expectation: + *

+ * With the following policy entries set, would expect the duplicate message to + * be read from the store and dispatched to the consumer - where the duplicate + * could be detected by consumer. + *

+ * PolicyEntry policy = new PolicyEntry(); policy.setQueue(">"); + * policy.setEnableAudit(false); policy.setUseCache(false); + * policy.setExpireMessagesPeriod(0); + *

+ *

+ * Note 1: Network needs to use replaywhenNoConsumers so enabling the + * networkAudit to avoid this scenario is not feasible. + *

+ * NOTE 2: Added a custom plugin to the consumerBroker so that the + * consumerBroker shutdown will occur after a message has been persisted to + * consumerBroker store but before an ACK is sent back to ProducerBroker. This + * is just a hack to ensure producerBroker will resend the message after + * shutdown. + */ + +@RunWith(value = Parameterized.class) +public class AMQ4952Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ4952Test.class); + + protected static final int MESSAGE_COUNT = 1; + + protected BrokerService consumerBroker; + protected BrokerService producerBroker; + + protected ActiveMQQueue QUEUE_NAME = new ActiveMQQueue("duptest.store"); + + private final CountDownLatch stopConsumerBroker = new CountDownLatch(1); + private final CountDownLatch consumerBrokerRestarted = new CountDownLatch(1); + private final CountDownLatch consumerRestartedAndMessageForwarded = new CountDownLatch(1); + + private EmbeddedDataSource localDataSource; + + @Parameterized.Parameter(0) + public boolean enableCursorAudit; + + @Parameterized.Parameters(name = "enableAudit={0}") + public static Iterable getTestParameters() { + return Arrays.asList(new Object[][] { { Boolean.TRUE }, { Boolean.FALSE } }); + } + + @Test + public void testConsumerBrokerRestart() throws Exception { + + Callable consumeMessageTask = new Callable() { + @Override + public Object call() throws Exception { + + int receivedMessageCount = 0; + + ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:2006)?randomize=false&backup=false"); + Connection consumerConnection = consumerFactory.createConnection(); + + try { + + consumerConnection.setClientID("consumer"); + consumerConnection.start(); + + Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer messageConsumer = consumerSession.createConsumer(QUEUE_NAME); + + while (true) { + TextMessage textMsg = (TextMessage) messageConsumer.receive(5000); + + if (textMsg == null) { + return receivedMessageCount; + } + + receivedMessageCount++; + LOG.info("*** receivedMessageCount {} message has MessageID {} ", receivedMessageCount, textMsg.getJMSMessageID()); + + // 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); + } + + textMsg.acknowledge(); + } + } finally { + consumerConnection.close(); + } + } + }; + + Runnable consumerBrokerResetTask = new Runnable() { + @Override + public void run() { + + try { + // wait for signal + stopConsumerBroker.await(); + + LOG.info("********* STOPPING CONSUMER BROKER"); + + consumerBroker.stop(); + consumerBroker.waitUntilStopped(); + + LOG.info("***** STARTING CONSUMER BROKER"); + // do not delete messages on startup + consumerBroker = createConsumerBroker(false); + + 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); + } + + } + }; + + ExecutorService executor = Executors.newFixedThreadPool(2); + + // start consumerBroker start/stop task + executor.execute(consumerBrokerResetTask); + + // start consuming messages + Future numberOfConsumedMessage = executor.submit(consumeMessageTask); + + produceMessages(); + + // Wait for consumer to finish + int totalMessagesConsumed = numberOfConsumedMessage.get(); + + StringBuffer contents = new StringBuffer(); + boolean messageInStore = isMessageInJDBCStore(localDataSource, contents); + LOG.debug("****number of messages received " + totalMessagesConsumed); + + assertEquals("number of messages received", 2, totalMessagesConsumed); + assertEquals("messages left in store", true, messageInStore); + assertTrue("message is in dlq: " + contents.toString(), contents.toString().contains("DLQ")); + } + + private void produceMessages() throws JMSException { + + ActiveMQConnectionFactory producerFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:2003)?randomize=false&backup=false"); + Connection producerConnection = producerFactory.createConnection(); + + try { + producerConnection.setClientID("producer"); + producerConnection.start(); + + 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); + remoteProducer.send(msg); + i++; + } + + } finally { + producerConnection.close(); + } + } + + @Before + public void setUp() throws Exception { + LOG.debug("Running with enableCursorAudit set to {}", this.enableCursorAudit); + doSetUp(); + } + + @After + public void tearDown() throws Exception { + doTearDown(); + } + + protected void doTearDown() throws Exception { + + try { + producerBroker.stop(); + } catch (Exception ex) { + } + try { + consumerBroker.stop(); + } catch (Exception ex) { + } + } + + protected void doSetUp() throws Exception { + producerBroker = createProducerBroker(); + consumerBroker = createConsumerBroker(true); + } + + /** + * Producer broker listens on localhost:2003 networks to consumerBroker - + * localhost:2006 + * + * @return + * @throws Exception + */ + protected BrokerService createProducerBroker() throws Exception { + + String networkToPorts[] = new String[] { "2006" }; + HashMap networkProps = new HashMap(); + + networkProps.put("networkTTL", "10"); + networkProps.put("conduitSubscriptions", "true"); + networkProps.put("decreaseNetworkConsumerPriority", "true"); + networkProps.put("dynamicOnly", "true"); + + 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(); + 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 })); + } + + // Persistence adapter + + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource remoteDataSource = new EmbeddedDataSource(); + remoteDataSource.setDatabaseName("target/derbyDBRemoteBroker"); + remoteDataSource.setCreateDatabase("create"); + jdbc.setDataSource(remoteDataSource); + broker.setPersistenceAdapter(jdbc); + + // set Policy entries + PolicyEntry policy = new PolicyEntry(); + + policy.setQueue(">"); + policy.setEnableAudit(false); + policy.setUseCache(false); + policy.setExpireMessagesPeriod(0); + + // set replay with no consumers + ConditionalNetworkBridgeFilterFactory conditionalNetworkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); + conditionalNetworkBridgeFilterFactory.setReplayWhenNoConsumers(true); + policy.setNetworkBridgeFilterFactory(conditionalNetworkBridgeFilterFactory); + + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + + broker.start(); + broker.waitUntilStarted(); + + return broker; + } + + /** + * consumerBroker - listens on localhost:2006 + * + * @param deleteMessages + * - drop messages when broker instance is created + * @return + * @throws Exception + */ + protected BrokerService createConsumerBroker(boolean deleteMessages) throws Exception { + + String scheme = "tcp"; + String listenPort = "2006"; + + 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(); + transportConnectors.add(transportConnector); + broker.setTransportConnectors(transportConnectors); + + // policy entries + + PolicyEntry policy = new PolicyEntry(); + + policy.setQueue(">"); + policy.setEnableAudit(enableCursorAudit); + policy.setExpireMessagesPeriod(0); + + // set replay with no consumers + ConditionalNetworkBridgeFilterFactory conditionalNetworkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); + conditionalNetworkBridgeFilterFactory.setReplayWhenNoConsumers(true); + policy.setNetworkBridgeFilterFactory(conditionalNetworkBridgeFilterFactory); + + PolicyMap pMap = new PolicyMap(); + + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + + // Persistence adapter + JDBCPersistenceAdapter localJDBCPersistentAdapter = new JDBCPersistenceAdapter(); + EmbeddedDataSource localDataSource = new EmbeddedDataSource(); + localDataSource.setDatabaseName("target/derbyDBLocalBroker"); + localDataSource.setCreateDatabase("create"); + localJDBCPersistentAdapter.setDataSource(localDataSource); + broker.setPersistenceAdapter(localJDBCPersistentAdapter); + + if (deleteMessages) { + // no plugin on restart + broker.setPlugins(new BrokerPlugin[] { new MyTestPlugin() }); + } + + this.localDataSource = localDataSource; + + broker.start(); + broker.waitUntilStarted(); + + 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 { + + boolean tableHasData = false; + String query = "select * from ACTIVEMQ_MSGS"; + + java.sql.Connection conn = dataSource.getConnection(); + PreparedStatement s = conn.prepareStatement(query); + + ResultSet set = null; + + try { + StringBuffer headers = new StringBuffer(); + set = s.executeQuery(); + ResultSetMetaData metaData = set.getMetaData(); + for (int i = 1; i <= metaData.getColumnCount(); i++) { + + if (i == 1) { + headers.append("||"); + } + headers.append(metaData.getColumnName(i) + "||"); + } + LOG.error(headers.toString()); + + while (set.next()) { + tableHasData = true; + + for (int i = 1; i <= metaData.getColumnCount(); i++) { + if (i == 1) { + stringBuffer.append("|"); + } + stringBuffer.append(set.getString(i) + "|"); + } + LOG.error(stringBuffer.toString()); + } + } finally { + try { + set.close(); + } catch (Throwable ignore) { + } + try { + s.close(); + } catch (Throwable ignore) { + } + + conn.close(); + } + + return tableHasData; + } + + /** + * plugin used to ensure consumerbroker is restared before the network + * message from producerBroker is acked + */ + class MyTestPlugin implements BrokerPlugin { + + @Override + public Broker installPlugin(Broker broker) throws Exception { + return new MyTestBroker(broker); + } + } + + class MyTestBroker extends BrokerFilter { + + public MyTestBroker(Broker next) { + super(next); + } + + @Override + public void send(ProducerBrokerExchange producerExchange, org.apache.activemq.command.Message messageSend) throws Exception { + + super.send(producerExchange, messageSend); + LOG.error("Stopping broker on send: " + messageSend.getMessageId().getProducerSequenceId()); + stopConsumerBroker.countDown(); + producerExchange.getConnectionContext().setDontSendReponse(true); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5035Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5035Test.java new file mode 100644 index 0000000000..13ddd30c4f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5035Test.java @@ -0,0 +1,83 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerViewMBean; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ5035Test { + + private static final String CLIENT_ID = "amq-test-client-id"; + private static final String DURABLE_SUB_NAME = "testDurable"; + + private final String xbean = "xbean:"; + private final String confBase = "src/test/resources/org/apache/activemq/bugs/amq5035"; + + private static BrokerService brokerService; + private String connectionUri; + + @Before + public void setUp() throws Exception { + brokerService = BrokerFactory.createBroker(xbean + confBase + "/activemq.xml"); + connectionUri = brokerService.getTransportConnectorByScheme("tcp").getPublishableConnectString(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.start(); + brokerService.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + @Test + public void testFoo() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + Connection connection = factory.createConnection(); + connection.setClientID(CLIENT_ID); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("Test.Topic"); + MessageConsumer consumer = session.createDurableSubscriber(topic, DURABLE_SUB_NAME); + consumer.close(); + + BrokerViewMBean brokerView = getBrokerView(DURABLE_SUB_NAME); + brokerView.destroyDurableSubscriber(CLIENT_ID, DURABLE_SUB_NAME); + } + + private BrokerViewMBean getBrokerView(String testDurable) throws MalformedObjectNameException { + ObjectName brokerName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost"); + BrokerViewMBean view = (BrokerViewMBean) brokerService.getManagementContext().newProxyInstance(brokerName, BrokerViewMBean.class, true); + assertNotNull(view); + return view; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5136Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5136Test.java new file mode 100644 index 0000000000..c2cb11edd0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5136Test.java @@ -0,0 +1,95 @@ +/** + * 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.bugs; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AMQ5136Test { + + BrokerService brokerService; + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.start(); + } + + @After + public void stopBroker() throws Exception { + brokerService.stop(); + } + + @Test + public void memoryUsageOnCommit() throws Exception { + sendMessagesAndAssertMemoryUsage(new TransactionHandler() { + @Override + public void finishTransaction(Session session) throws JMSException { + session.commit(); + } + }); + } + + @Test + public void memoryUsageOnRollback() throws Exception { + sendMessagesAndAssertMemoryUsage(new TransactionHandler() { + @Override + public void finishTransaction(Session session) throws JMSException { + session.rollback(); + } + }); + } + + private void sendMessagesAndAssertMemoryUsage(TransactionHandler transactionHandler) throws Exception { + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Topic destination = session.createTopic("ActiveMQBug"); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < 100; i++) { + BytesMessage message = session.createBytesMessage(); + message.writeBytes(generateBytes()); + producer.send(message); + transactionHandler.finishTransaction(session); + } + connection.close(); + org.junit.Assert.assertEquals(0, BrokerRegistry.getInstance().findFirst().getSystemUsage().getMemoryUsage().getPercentUsage()); + } + + private byte[] generateBytes() { + byte[] bytes = new byte[100000]; + for (int i = 0; i < 100000; i++) { + bytes[i] = (byte) i; + } + return bytes; + } + + private static interface TransactionHandler { + void finishTransaction(Session session) throws JMSException; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5212Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5212Test.java new file mode 100644 index 0000000000..4c0765538e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5212Test.java @@ -0,0 +1,225 @@ +/** + * 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.bugs; + +import java.util.Arrays; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQMessageProducer; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(value = Parameterized.class) +public class AMQ5212Test { + + BrokerService brokerService; + + @Parameterized.Parameter(0) + public boolean concurrentStoreAndDispatchQ = true; + + @Parameterized.Parameters(name = "concurrentStoreAndDispatch={0}") + public static Iterable getTestParameters() { + return Arrays.asList(new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}}); + } + + @Before + public void setUp() throws Exception { + start(true); + } + + public void start(boolean deleteAllMessages) throws Exception { + brokerService = new BrokerService(); + if (deleteAllMessages) { + brokerService.deleteAllMessages(); + } + ((KahaDBPersistenceAdapter)brokerService.getPersistenceAdapter()).setConcurrentStoreAndDispatchQueues(concurrentStoreAndDispatchQ); + brokerService.addConnector("tcp://localhost:0"); + brokerService.setAdvisorySupport(false); + brokerService.start(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + } + + @Test + public void verifyDuplicateSuppressionWithConsumer() throws Exception { + doVerifyDuplicateSuppression(100, 100, true); + } + + @Test + public void verifyDuplicateSuppression() throws Exception { + doVerifyDuplicateSuppression(100, 100, false); + } + + public void doVerifyDuplicateSuppression(final int numToSend, final int expectedTotalEnqueue, final boolean demand) throws Exception { + final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerService.getTransportConnectors().get(0).getPublishableConnectString()); + connectionFactory.setCopyMessageOnSend(false); + connectionFactory.setWatchTopicAdvisories(false); + + final int concurrency = 40; + final AtomicInteger workCount = new AtomicInteger(numToSend); + ExecutorService executorService = Executors.newFixedThreadPool(concurrency); + for (int i = 0; i < concurrency; i++) { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + int i; + while ((i = workCount.getAndDecrement()) > 0) { + ActiveMQConnection activeMQConnection = (ActiveMQConnection) connectionFactory.createConnection(); + activeMQConnection.start(); + ActiveMQSession activeMQSession = (ActiveMQSession) activeMQConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + ActiveMQQueue dest = new ActiveMQQueue("queue-" + i + "-" + + AMQ5212Test.class.getSimpleName()); + ActiveMQMessageProducer activeMQMessageProducer = (ActiveMQMessageProducer) activeMQSession.createProducer(dest); + if (demand) { + // create demand so page in will happen + activeMQSession.createConsumer(dest); + } + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setDestination(dest); + activeMQMessageProducer.send(message, null); + + // send a duplicate + activeMQConnection.syncSendPacket(message); + activeMQConnection.close(); + + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + TimeUnit.SECONDS.sleep(1); + executorService.shutdown(); + executorService.awaitTermination(5, TimeUnit.MINUTES); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return expectedTotalEnqueue == brokerService.getAdminView().getTotalEnqueueCount(); + } + }); + assertEquals("total enqueue as expected", expectedTotalEnqueue, brokerService.getAdminView().getTotalEnqueueCount()); + } + + @Test + public void verifyConsumptionOnDuplicate() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerService.getTransportConnectors().get(0).getPublishableConnectString()); + connectionFactory.setCopyMessageOnSend(false); + connectionFactory.setWatchTopicAdvisories(false); + + ActiveMQConnection activeMQConnection = (ActiveMQConnection) connectionFactory.createConnection(); + activeMQConnection.start(); + ActiveMQSession activeMQSession = (ActiveMQSession) activeMQConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQQueue dest = new ActiveMQQueue("Q"); + ActiveMQMessageProducer activeMQMessageProducer = (ActiveMQMessageProducer) activeMQSession.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setDestination(dest); + activeMQMessageProducer.send(message, null); + + // send a duplicate + activeMQConnection.syncSendPacket(message); + + activeMQConnection.close(); + + // verify original can be consumed after restart + brokerService.stop(); + brokerService.start(false); + + connectionFactory = new ActiveMQConnectionFactory(brokerService.getTransportConnectors().get(0).getPublishableConnectString()); + connectionFactory.setCopyMessageOnSend(false); + connectionFactory.setWatchTopicAdvisories(false); + + activeMQConnection = (ActiveMQConnection) connectionFactory.createConnection(); + activeMQConnection.start(); + activeMQSession = (ActiveMQSession) activeMQConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer messageConsumer = activeMQSession.createConsumer(dest); + Message received = messageConsumer.receive(4000); + assertNotNull("Got message", received); + assertEquals("match", message.getJMSMessageID(), received.getJMSMessageID()); + + activeMQConnection.close(); + } + + @Test + public void verifyClientAckConsumptionOnDuplicate() throws Exception { + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerService.getTransportConnectors().get(0).getPublishableConnectString()); + connectionFactory.setCopyMessageOnSend(false); + connectionFactory.setWatchTopicAdvisories(false); + + ActiveMQConnection activeMQConnection = (ActiveMQConnection) connectionFactory.createConnection(); + activeMQConnection.start(); + ActiveMQSession activeMQSession = (ActiveMQSession) activeMQConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + ActiveMQQueue dest = new ActiveMQQueue("Q"); + + MessageConsumer messageConsumer = activeMQSession.createConsumer(dest); + + ActiveMQMessageProducer activeMQMessageProducer = (ActiveMQMessageProducer) activeMQSession.createProducer(dest); + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setDestination(dest); + activeMQMessageProducer.send(message, null); + + // send a duplicate + activeMQConnection.syncSendPacket(message); + + + Message received = messageConsumer.receive(4000); + assertNotNull("Got message", received); + assertEquals("match", message.getJMSMessageID(), received.getJMSMessageID()); + messageConsumer.close(); + + + messageConsumer = activeMQSession.createConsumer(dest); + received = messageConsumer.receive(4000); + assertNotNull("Got message", received); + assertEquals("match", message.getJMSMessageID(), received.getJMSMessageID()); + received.acknowledge(); + + activeMQConnection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266SingleDestTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266SingleDestTest.java new file mode 100644 index 0000000000..0d7f44bfee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266SingleDestTest.java @@ -0,0 +1,602 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; + +/** + Non transactional concurrent producer/consumer to single dest + */ +@RunWith(Parameterized.class) +public class AMQ5266SingleDestTest { + static Logger LOG = LoggerFactory.getLogger(AMQ5266SingleDestTest.class); + String activemqURL; + BrokerService brokerService; + + public int numDests = 1; + public int messageSize = 10*1000; + + @Parameterized.Parameter(0) + public int publisherMessagesPerThread = 1000; + + @Parameterized.Parameter(1) + public int publisherThreadCount = 20; + + @Parameterized.Parameter(2) + public int consumerThreadsPerQueue = 5; + + @Parameterized.Parameter(3) + public int destMemoryLimit = 50 * 1024; + + @Parameterized.Parameter(4) + public boolean useCache = true; + + @Parameterized.Parameter(5) + public TestSupport.PersistenceAdapterChoice persistenceAdapterChoice = TestSupport.PersistenceAdapterChoice.KahaDB; + + @Parameterized.Parameter(6) + public boolean optimizeDispatch = false; + + @Parameterized.Parameters(name="#{0},producerThreads:{1},consumerThreads:{2},mL:{3},useCache:{4},useDefaultStore:{5},optimizedDispatch:{6}") + public static Iterable parameters() { + return Arrays.asList(new Object[][]{ + {1000, 40, 40, 1024*1024*1, true, TestSupport.PersistenceAdapterChoice.KahaDB, false}, + {1000, 40, 40, 1024*1024*1, true, TestSupport.PersistenceAdapterChoice.LevelDB, false}, + {1000, 40, 40, 1024*1024*1, true, TestSupport.PersistenceAdapterChoice.JDBC, false}, + }); + } + + public int consumerBatchSize = 25; + + @BeforeClass + public static void derbyTestMode() throws Exception { + System.setProperty("derby.system.durability","test"); + } + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + + TestSupport.setPersistenceAdapter(brokerService, persistenceAdapterChoice); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setUseJmx(false); + brokerService.setAdvisorySupport(false); + + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setUseConsumerPriority(false); // java.lang.IllegalArgumentException: Comparison method violates its general contract! + defaultEntry.setMaxProducersToAudit(publisherThreadCount); + defaultEntry.setEnableAudit(true); + defaultEntry.setUseCache(useCache); + defaultEntry.setMaxPageSize(1000); + defaultEntry.setOptimizedDispatch(optimizeDispatch); + defaultEntry.setMemoryLimit(destMemoryLimit); + defaultEntry.setExpireMessagesPeriod(0); + policyMap.setDefaultEntry(defaultEntry); + brokerService.setDestinationPolicy(policyMap); + + brokerService.getSystemUsage().getMemoryUsage().setLimit(64 * 1024 * 1024); + + TransportConnector transportConnector = brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.start(); + activemqURL = transportConnector.getPublishableConnectString(); + activemqURL += "?jms.watchTopicAdvisories=false"; // ensure all messages are queue or dlq messages + } + + @After + public void stopBroker() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + @Test + public void test() throws Exception { + + String activemqQueues = "activemq"; + for (int i=1;i> entry : consumer.getIDs().entrySet()) { + + List idList = entry.getValue(); + + int distinctConsumed = new TreeSet(idList).size(); + + StringBuilder sb = new StringBuilder(); + sb.append(" Queue: " + entry.getKey() + + " -> Total Messages Consumed: " + idList.size() + + ", Distinct IDs Consumed: " + distinctConsumed); + + int diff = distinctPublishedCount - distinctConsumed; + sb.append(" ( " + (diff > 0 ? diff : "NO") + " STUCK MESSAGES " + " ) "); + LOG.info(sb.toString()); + + assertEquals("expect to get all messages!", 0, diff); + + } + + // verify empty dlq + assertEquals("No pending messages", 0l, ((RegionBroker) brokerService.getRegionBroker()).getDestinationStatistics().getMessages().getCount()); + } + + public class ExportQueuePublisher { + + private final String amqUser = ActiveMQConnection.DEFAULT_USER; + private final String amqPassword = ActiveMQConnection.DEFAULT_PASSWORD; + private ActiveMQConnectionFactory connectionFactory = null; + private String activemqURL = null; + private String activemqQueues = null; + // Collection of distinct IDs that the publisher has published. + // After a message is published, its UUID will be written to this list for tracking. + // This list of IDs (or distinct count) will be used to compare to the consumed list of IDs. + //private Set ids = Collections.synchronizedSet(new TreeSet()); + private List ids = Collections.synchronizedList(new ArrayList()); + private List threads; + + public ExportQueuePublisher(String activemqURL, String activemqQueues, int messagesPerThread, int threadCount) throws Exception { + + this.activemqURL = activemqURL; + this.activemqQueues = activemqQueues; + + threads = new ArrayList(); + + // Build the threads and tell them how many messages to publish + for (int i = 0; i < threadCount; i++) { + PublisherThread pt = new PublisherThread(messagesPerThread); + threads.add(pt); + } + } + + public List getIDs() { + return ids; + } + + // Kick off threads + public void start() throws Exception { + + for (PublisherThread pt : threads) { + pt.start(); + } + } + + // Wait for threads to complete. They will complete once they've published all of their messages. + public void waitForCompletion() throws Exception { + + for (PublisherThread pt : threads) { + pt.join(); + pt.close(); + } + } + + private Session newSession(QueueConnection queueConnection) throws Exception { + return queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + private synchronized QueueConnection newQueueConnection() throws Exception { + + if (connectionFactory == null) { + connectionFactory = new ActiveMQConnectionFactory(amqUser, amqPassword, activemqURL); + } + + // Set the redelivery count to -1 (infinite), or else messages will start dropping + // after the queue has had a certain number of failures (default is 6) + RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy(); + policy.setMaximumRedeliveries(-1); + + QueueConnection amqConnection = connectionFactory.createQueueConnection(); + amqConnection.start(); + return amqConnection; + } + + private class PublisherThread extends Thread { + + private int count; + private QueueConnection qc; + private Session session; + private MessageProducer mp; + + private PublisherThread(int count) throws Exception { + + this.count = count; + + // Each Thread has its own Connection and Session, so no sync worries + qc = newQueueConnection(); + session = newSession(qc); + + // In our code, when publishing to multiple queues, + // we're using composite destinations like below + Queue q = new ActiveMQQueue(activemqQueues); + mp = session.createProducer(q); + } + + public void run() { + + try { + + // Loop until we've published enough messages + while (count-- > 0) { + + TextMessage tm = session.createTextMessage(getMessageText()); + String id = UUID.randomUUID().toString(); + tm.setStringProperty("KEY", id); + ids.add(id); // keep track of the key to compare against consumer + + mp.send(tm); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // Called by waitForCompletion + public void close() { + + try { + mp.close(); + } catch (Exception e) { + } + + try { + session.close(); + } catch (Exception e) { + } + + try { + qc.close(); + } catch (Exception e) { + } + } + } + + } + + String messageText; + private String getMessageText() { + + if (messageText == null) { + + synchronized (this) { + + if (messageText == null) { + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < messageSize; i++) { + sb.append("X"); + } + messageText = sb.toString(); + } + } + } + + return messageText; + } + + + public class ExportQueueConsumer { + + private final String amqUser = ActiveMQConnection.DEFAULT_USER; + private final String amqPassword = ActiveMQConnection.DEFAULT_PASSWORD; + private final int totalToExpect; + private ActiveMQConnectionFactory connectionFactory = null; + private String activemqURL = null; + private String activemqQueues = null; + private String[] queues = null; + // Map of IDs that were consumed, keyed by queue name. + // We'll compare these against what was published to know if any got stuck or dropped. + private Map> idsByQueue = new HashMap>(); + private Map> threads; + + public ExportQueueConsumer(String activemqURL, String activemqQueues, int threadsPerQueue, int batchSize, int totalToExpect) throws Exception { + + this.activemqURL = activemqURL; + this.activemqQueues = activemqQueues; + this.totalToExpect = totalToExpect; + + queues = this.activemqQueues.split(","); + + for (int i = 0; i < queues.length; i++) { + queues[i] = queues[i].trim(); + } + + threads = new HashMap>(); + + // For each queue, create a list of threads and set up the list of ids + for (String q : queues) { + + List list = new ArrayList(); + + idsByQueue.put(q, Collections.synchronizedList(new ArrayList())); + + for (int i = 0; i < threadsPerQueue; i++) { + list.add(new ConsumerThread(q, batchSize)); + } + + threads.put(q, list); + } + } + + public Map> getIDs() { + return idsByQueue; + } + + // Start the threads + public void start() throws Exception { + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.start(); + } + } + } + + // Tell the threads to stop + // Then wait for them to stop + public void shutdown() throws Exception { + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.shutdown(); + } + } + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.join(); + } + } + } + + private Session newSession(QueueConnection queueConnection) throws Exception { + return queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + private synchronized QueueConnection newQueueConnection() throws Exception { + + if (connectionFactory == null) { + connectionFactory = new ActiveMQConnectionFactory(amqUser, amqPassword, activemqURL); + } + + // Set the redelivery count to -1 (infinite), or else messages will start dropping + // after the queue has had a certain number of failures (default is 6) + RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy(); + policy.setMaximumRedeliveries(-1); + + QueueConnection amqConnection = connectionFactory.createQueueConnection(); + amqConnection.start(); + return amqConnection; + } + + public boolean completed() { + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + if (ct.isAlive()) { + LOG.info("thread for {} is still alive.", ct.qName); + return false; + } + } + } + return true; + } + + private class ConsumerThread extends Thread { + + private int batchSize; + private QueueConnection qc; + private Session session; + private MessageConsumer mc; + private List idList; + private boolean shutdown = false; + private String qName; + + private ConsumerThread(String queueName, int batchSize) throws Exception { + + this.batchSize = batchSize; + + // Each thread has its own connection and session + qName = queueName; + qc = newQueueConnection(); + session = newSession(qc); + Queue q = session.createQueue(queueName + "?consumer.prefetchSize=" + batchSize); + mc = session.createConsumer(q); + + idList = idsByQueue.get(queueName); + } + + public void run() { + + try { + + int count = 0; + + // Keep reading as long as it hasn't been told to shutdown + while (!shutdown) { + + if (idList.size() >= totalToExpect) { + LOG.info("Got {} for q: {}", +idList.size(), qName); + break; + } + Message m = mc.receive(4000); + + if (m != null) { + + // We received a non-null message, add the ID to our list + + idList.add(m.getStringProperty("KEY")); + + count++; + + // If we've reached our batch size, commit the batch and reset the count + + if (count == batchSize) { + count = 0; + } + } else { + + // We didn't receive anything this time, commit any current batch and reset the count + + count = 0; + + // Sleep a little before trying to read after not getting a message + + try { + if (idList.size() < totalToExpect) { + LOG.info("did not receive on {}, current count: {}", qName, idList.size()); + } + //sleep(3000); + } catch (Exception e) { + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + + // Once we exit, close everything + close(); + } + } + + public void shutdown() { + shutdown = true; + } + + public void close() { + + try { + mc.close(); + } catch (Exception e) { + } + + try { + session.close(); + } catch (Exception e) { + } + + try { + qc.close(); + } catch (Exception e) { + + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266StarvedConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266StarvedConsumerTest.java new file mode 100644 index 0000000000..f7409dd619 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266StarvedConsumerTest.java @@ -0,0 +1,620 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.jdbc.adapter.DefaultJDBCAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; + +/* + * pause producers if consumers stall and verify broker drained before resume + */ +@RunWith(Parameterized.class) +public class AMQ5266StarvedConsumerTest { + static Logger LOG = LoggerFactory.getLogger(AMQ5266StarvedConsumerTest.class); + String activemqURL; + BrokerService brokerService; + + public int messageSize = 1000; + + @Parameterized.Parameter(0) + public int publisherMessagesPerThread = 1000; + + @Parameterized.Parameter(1) + public int publisherThreadCount = 20; + + @Parameterized.Parameter(2) + public int consumerThreadsPerQueue = 5; + + @Parameterized.Parameter(3) + public int destMemoryLimit = 50 * 1024; + + @Parameterized.Parameter(4) + public boolean useCache = true; + + @Parameterized.Parameter(5) + public TestSupport.PersistenceAdapterChoice persistenceAdapterChoice = TestSupport.PersistenceAdapterChoice.KahaDB; + + @Parameterized.Parameter(6) + public boolean optimizeDispatch = false; + private AtomicBoolean didNotReceive = new AtomicBoolean(false); + + @Parameterized.Parameters(name="#{0},producerThreads:{1},consumerThreads:{2},mL:{3},useCache:{4},store:{5},optimizedDispatch:{6}") + public static Iterable parameters() { + return Arrays.asList(new Object[][]{ + {1000, 40, 5, 1024*1024, false, TestSupport.PersistenceAdapterChoice.KahaDB, true}, + {1000, 40, 5, 1024*1024, false, TestSupport.PersistenceAdapterChoice.LevelDB, true}, + {1000, 40, 5, 1024*1024, false, TestSupport.PersistenceAdapterChoice.JDBC, true}, + + {500, 20, 20, 1024*1024, false, TestSupport.PersistenceAdapterChoice.KahaDB, true}, + {500, 20, 20, 1024*1024, false, TestSupport.PersistenceAdapterChoice.LevelDB, true}, + {500, 20, 20, 1024*1024, false, TestSupport.PersistenceAdapterChoice.JDBC, true}, + }); + } + + public int consumerBatchSize = 5; + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + TestSupport.setPersistenceAdapter(brokerService, persistenceAdapterChoice); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setUseJmx(false); + brokerService.setAdvisorySupport(false); + + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setUseConsumerPriority(false); // java.lang.IllegalArgumentException: Comparison method violates its general contract! + defaultEntry.setMaxAuditDepth(publisherThreadCount); + defaultEntry.setEnableAudit(true); + defaultEntry.setUseCache(useCache); + defaultEntry.setMaxPageSize(1000); + defaultEntry.setOptimizedDispatch(optimizeDispatch); + defaultEntry.setMemoryLimit(destMemoryLimit); + defaultEntry.setExpireMessagesPeriod(0); + policyMap.setDefaultEntry(defaultEntry); + brokerService.setDestinationPolicy(policyMap); + + brokerService.getSystemUsage().getMemoryUsage().setLimit(512 * 1024 * 1024); + + TransportConnector transportConnector = brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.start(); + activemqURL = transportConnector.getPublishableConnectString(); + } + + @After + public void stopBroker() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + CyclicBarrier globalProducerHalt = new CyclicBarrier(publisherThreadCount, new Runnable() { + @Override + public void run() { + // wait for queue size to go to zero + try { + while (((RegionBroker)brokerService.getRegionBroker()).getDestinationStatistics().getMessages().getCount() > 0) { + LOG.info("Total messageCount: " + ((RegionBroker)brokerService.getRegionBroker()).getDestinationStatistics().getMessages().getCount()); + TimeUnit.SECONDS.sleep(5); + } + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + }); + + @Test(timeout = 30 * 60 * 1000) + public void test() throws Exception { + + String activemqQueues = "activemq,activemq2,activemq3,activemq4";//,activemq5,activemq6,activemq7,activemq8,activemq9"; + + int consumerWaitForConsumption = 5 * 60 * 1000; + + ExportQueuePublisher publisher = null; + ExportQueueConsumer consumer = null; + + LOG.info("Publisher will publish " + (publisherMessagesPerThread * publisherThreadCount) + " messages to each queue specified."); + LOG.info("\nBuilding Publisher..."); + + publisher = new ExportQueuePublisher(activemqURL, activemqQueues, publisherMessagesPerThread, publisherThreadCount); + + LOG.info("Building Consumer..."); + + consumer = new ExportQueueConsumer(activemqURL, activemqQueues, consumerThreadsPerQueue, consumerBatchSize, publisherMessagesPerThread * publisherThreadCount); + + + LOG.info("Starting Publisher..."); + + publisher.start(); + + LOG.info("Starting Consumer..."); + + consumer.start(); + + int distinctPublishedCount = 0; + + + LOG.info("Waiting For Publisher Completion..."); + + publisher.waitForCompletion(); + + List publishedIds = publisher.getIDs(); + distinctPublishedCount = new TreeSet(publishedIds).size(); + + LOG.info("Publisher Complete. Published: " + publishedIds.size() + ", Distinct IDs Published: " + distinctPublishedCount); + + + long endWait = System.currentTimeMillis() + consumerWaitForConsumption; + while (!consumer.completed() && System.currentTimeMillis() < endWait) { + try { + int secs = (int) (endWait - System.currentTimeMillis()) / 1000; + LOG.info("Waiting For Consumer Completion. Time left: " + secs + " secs"); + Thread.sleep(10000); + } catch (Exception e) { + } + } + + LOG.info("\nConsumer Complete: " + consumer.completed() +", Shutting Down."); + + consumer.shutdown(); + + + LOG.info("Consumer Stats:"); + + for (Map.Entry> entry : consumer.getIDs().entrySet()) { + + List idList = entry.getValue(); + + int distinctConsumed = new TreeSet(idList).size(); + + StringBuilder sb = new StringBuilder(); + sb.append(" Queue: " + entry.getKey() + + " -> Total Messages Consumed: " + idList.size() + + ", Distinct IDs Consumed: " + distinctConsumed); + + int diff = distinctPublishedCount - distinctConsumed; + sb.append(" ( " + (diff > 0 ? diff : "NO") + " STUCK MESSAGES " + " ) "); + LOG.info(sb.toString()); + + assertEquals("expect to get all messages!", 0, diff); + + } + } + + public class ExportQueuePublisher { + + private final String amqUser = ActiveMQConnection.DEFAULT_USER; + private final String amqPassword = ActiveMQConnection.DEFAULT_PASSWORD; + private ActiveMQConnectionFactory connectionFactory = null; + private String activemqURL = null; + private String activemqQueues = null; + // Collection of distinct IDs that the publisher has published. + // After a message is published, its UUID will be written to this list for tracking. + // This list of IDs (or distinct count) will be used to compare to the consumed list of IDs. + //private Set ids = Collections.synchronizedSet(new TreeSet()); + private List ids = Collections.synchronizedList(new ArrayList()); + private List threads; + + public ExportQueuePublisher(String activemqURL, String activemqQueues, int messagesPerThread, int threadCount) throws Exception { + + this.activemqURL = activemqURL; + this.activemqQueues = activemqQueues; + + threads = new ArrayList(); + + // Build the threads and tell them how many messages to publish + for (int i = 0; i < threadCount; i++) { + PublisherThread pt = new PublisherThread(messagesPerThread); + threads.add(pt); + } + } + + public List getIDs() { + return ids; + } + + // Kick off threads + public void start() throws Exception { + + for (PublisherThread pt : threads) { + pt.start(); + } + } + + // Wait for threads to complete. They will complete once they've published all of their messages. + public void waitForCompletion() throws Exception { + + for (PublisherThread pt : threads) { + pt.join(); + pt.close(); + } + } + + private Session newSession(QueueConnection queueConnection) throws Exception { + return queueConnection.createSession(true, Session.SESSION_TRANSACTED); + } + + private synchronized QueueConnection newQueueConnection() throws Exception { + + if (connectionFactory == null) { + connectionFactory = new ActiveMQConnectionFactory(amqUser, amqPassword, activemqURL); + connectionFactory.setWatchTopicAdvisories(false); + } + + // Set the redelivery count to -1 (infinite), or else messages will start dropping + // after the queue has had a certain number of failures (default is 6) + RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy(); + policy.setMaximumRedeliveries(-1); + + QueueConnection amqConnection = connectionFactory.createQueueConnection(); + amqConnection.start(); + return amqConnection; + } + + private class PublisherThread extends Thread { + + private int count; + private QueueConnection qc; + private Session session; + private MessageProducer mp; + private Queue q; + + private PublisherThread(int count) throws Exception { + + this.count = count; + + // Each Thread has its own Connection and Session, so no sync worries + qc = newQueueConnection(); + session = newSession(qc); + + // In our code, when publishing to multiple queues, + // we're using composite destinations like below + q = new ActiveMQQueue(activemqQueues); + mp = session.createProducer(null); + } + + public void run() { + + try { + + // Loop until we've published enough messages + while (count-- > 0) { + + TextMessage tm = session.createTextMessage(getMessageText()); + String id = UUID.randomUUID().toString(); + tm.setStringProperty("KEY", id); + ids.add(id); // keep track of the key to compare against consumer + + mp.send(q, tm); + session.commit(); + + if (didNotReceive.get()) { + globalProducerHalt.await(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // Called by waitForCompletion + public void close() { + + try { + mp.close(); + } catch (Exception e) { + } + + try { + session.close(); + } catch (Exception e) { + } + + try { + qc.close(); + } catch (Exception e) { + } + } + } + + } + + String messageText; + private String getMessageText() { + + if (messageText == null) { + + synchronized (this) { + + if (messageText == null) { + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < messageSize; i++) { + sb.append("X"); + } + messageText = sb.toString(); + } + } + } + + return messageText; + } + + + public class ExportQueueConsumer { + + private final String amqUser = ActiveMQConnection.DEFAULT_USER; + private final String amqPassword = ActiveMQConnection.DEFAULT_PASSWORD; + private final int totalToExpect; + private ActiveMQConnectionFactory connectionFactory = null; + private String activemqURL = null; + private String activemqQueues = null; + private String[] queues = null; + // Map of IDs that were consumed, keyed by queue name. + // We'll compare these against what was published to know if any got stuck or dropped. + private Map> idsByQueue = new HashMap>(); + private Map> threads; + + public ExportQueueConsumer(String activemqURL, String activemqQueues, int threadsPerQueue, int batchSize, int totalToExpect) throws Exception { + + this.activemqURL = activemqURL; + this.activemqQueues = activemqQueues; + this.totalToExpect = totalToExpect; + + queues = this.activemqQueues.split(","); + + for (int i = 0; i < queues.length; i++) { + queues[i] = queues[i].trim(); + } + + threads = new HashMap>(); + + // For each queue, create a list of threads and set up the list of ids + for (String q : queues) { + + List list = new ArrayList(); + + idsByQueue.put(q, Collections.synchronizedList(new ArrayList())); + + for (int i = 0; i < threadsPerQueue; i++) { + list.add(new ConsumerThread(q, batchSize)); + } + + threads.put(q, list); + } + } + + public Map> getIDs() { + return idsByQueue; + } + + // Start the threads + public void start() throws Exception { + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.start(); + } + } + } + + // Tell the threads to stop + // Then wait for them to stop + public void shutdown() throws Exception { + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.shutdown(); + } + } + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.join(); + } + } + } + + private Session newSession(QueueConnection queueConnection) throws Exception { + return queueConnection.createSession(true, Session.SESSION_TRANSACTED); + } + + private synchronized QueueConnection newQueueConnection() throws Exception { + + if (connectionFactory == null) { + connectionFactory = new ActiveMQConnectionFactory(amqUser, amqPassword, activemqURL); + connectionFactory.setWatchTopicAdvisories(false); + } + + // Set the redelivery count to -1 (infinite), or else messages will start dropping + // after the queue has had a certain number of failures (default is 6) + RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy(); + policy.setMaximumRedeliveries(-1); + + QueueConnection amqConnection = connectionFactory.createQueueConnection(); + amqConnection.start(); + return amqConnection; + } + + public boolean completed() { + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + if (ct.isAlive()) { + LOG.info("thread for {} is still alive.", ct.qName); + return false; + } + } + } + return true; + } + + private class ConsumerThread extends Thread { + + private int batchSize; + private QueueConnection qc; + private Session session; + private MessageConsumer mc; + private List idList; + private boolean shutdown = false; + private String qName; + + private ConsumerThread(String queueName, int batchSize) throws Exception { + + this.batchSize = batchSize; + + // Each thread has its own connection and session + qName = queueName; + qc = newQueueConnection(); + session = newSession(qc); + Queue q = session.createQueue(queueName + "?consumer.prefetchSize=" + batchSize); + mc = session.createConsumer(q); + + idList = idsByQueue.get(queueName); + } + + public void run() { + + try { + + int count = 0; + + // Keep reading as long as it hasn't been told to shutdown + while (!shutdown) { + + if (idList.size() >= totalToExpect) { + LOG.info("Got {} for q: {}", +idList.size(), qName); + session.commit(); + break; + } + Message m = mc.receive(4000); + + if (m != null) { + + // We received a non-null message, add the ID to our list + + idList.add(m.getStringProperty("KEY")); + + count++; + + // If we've reached our batch size, commit the batch and reset the count + + if (count == batchSize) { + session.commit(); + count = 0; + } + } else { + + // We didn't receive anything this time, commit any current batch and reset the count + + session.commit(); + count = 0; + + // Sleep a little before trying to read after not getting a message + + try { + if (idList.size() < totalToExpect) { + LOG.info("did not receive on {}, current count: {}", qName, idList.size()); + didNotReceive.set(true); + } + //sleep(3000); + } catch (Exception e) { + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + + // Once we exit, close everything + close(); + } + } + + public void shutdown() { + shutdown = true; + } + + public void close() { + + try { + mc.close(); + } catch (Exception e) { + } + + try { + session.close(); + } catch (Exception e) { + } + + try { + qc.close(); + } catch (Exception e) { + + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266Test.java new file mode 100644 index 0000000000..e180746939 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5266Test.java @@ -0,0 +1,601 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; + +/** + * Stuck messages test client. + *

+ * Will kick of publisher and consumer simultaneously, and will usually result in stuck messages on the queue. + */ +@RunWith(Parameterized.class) +public class AMQ5266Test { + static Logger LOG = LoggerFactory.getLogger(AMQ5266Test.class); + String activemqURL = "tcp://localhost:61617"; + BrokerService brokerService; + + public int messageSize = 1000; + + @Parameterized.Parameter(0) + public int publisherMessagesPerThread = 1000; + + @Parameterized.Parameter(1) + public int publisherThreadCount = 20; + + @Parameterized.Parameter(2) + public int consumerThreadsPerQueue = 5; + + @Parameterized.Parameter(3) + public int destMemoryLimit = 50 * 1024; + + @Parameterized.Parameter(4) + public boolean useCache = true; + + @Parameterized.Parameter(5) + public TestSupport.PersistenceAdapterChoice persistenceAdapterChoice = TestSupport.PersistenceAdapterChoice.KahaDB; + + @Parameterized.Parameter(6) + public boolean optimizeDispatch = false; + + @Parameterized.Parameters(name="#{0},producerThreads:{1},consumerThreads:{2},mL:{3},useCache:{4},store:{5},optimizedDispatch:{6}") + public static Iterable parameters() { + return Arrays.asList(new Object[][]{ + {1, 1, 1, 50*1024, false, TestSupport.PersistenceAdapterChoice.JDBC, true}, + {1000, 20, 5, 50*1024, true, TestSupport.PersistenceAdapterChoice.JDBC, false}, + {100, 20, 5, 50*1024, false, TestSupport.PersistenceAdapterChoice.JDBC, false}, + {1000, 5, 20, 50*1024, true, TestSupport.PersistenceAdapterChoice.JDBC, false}, + {1000, 20, 20, 1024*1024, true, TestSupport.PersistenceAdapterChoice.JDBC, false}, + + {1, 1, 1, 50*1024, false, TestSupport.PersistenceAdapterChoice.KahaDB, true}, + {100, 5, 5, 50*1024, false, TestSupport.PersistenceAdapterChoice.KahaDB, false}, + {1000, 20, 5, 50*1024, true, TestSupport.PersistenceAdapterChoice.KahaDB, false}, + {100, 20, 5, 50*1024, false, TestSupport.PersistenceAdapterChoice.KahaDB, false}, + {1000, 5, 20, 50*1024, true, TestSupport.PersistenceAdapterChoice.KahaDB, false}, + {1000, 20, 20, 1024*1024, true, TestSupport.PersistenceAdapterChoice.KahaDB, false}, + + {1, 1, 1, 50*1024, false, TestSupport.PersistenceAdapterChoice.LevelDB, true}, + {100, 5, 5, 50*1024, false, TestSupport.PersistenceAdapterChoice.LevelDB, false}, + {1000, 20, 5, 50*1024, true, TestSupport.PersistenceAdapterChoice.LevelDB, false}, + {100, 20, 5, 50*1024, false, TestSupport.PersistenceAdapterChoice.LevelDB, false}, + {1000, 5, 20, 50*1024, true, TestSupport.PersistenceAdapterChoice.LevelDB, false}, + {1000, 20, 20, 1024*1024, true, TestSupport.PersistenceAdapterChoice.LevelDB, false}, + + }); + } + + public int consumerBatchSize = 5; + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + TestSupport.setPersistenceAdapter(brokerService, persistenceAdapterChoice); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setUseJmx(false); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setUseConsumerPriority(false); // java.lang.IllegalArgumentException: Comparison method violates its general contract! + defaultEntry.setMaxAuditDepth(publisherThreadCount); + defaultEntry.setEnableAudit(true); + defaultEntry.setUseCache(useCache); + defaultEntry.setMaxPageSize(1000); + defaultEntry.setOptimizedDispatch(optimizeDispatch); + defaultEntry.setMemoryLimit(destMemoryLimit); + defaultEntry.setExpireMessagesPeriod(0); + policyMap.setDefaultEntry(defaultEntry); + brokerService.setDestinationPolicy(policyMap); + + brokerService.getSystemUsage().getMemoryUsage().setLimit(512 * 1024 * 1024); + + TransportConnector transportConnector = brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.start(); + activemqURL = transportConnector.getPublishableConnectString(); + } + + @After + public void stopBroker() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + @Test + public void test() throws Exception { + + String activemqQueues = "activemq,activemq2";//,activemq3,activemq4,activemq5,activemq6,activemq7,activemq8,activemq9"; + + int consumerWaitForConsumption = 5 * 60 * 1000; + + ExportQueuePublisher publisher = null; + ExportQueueConsumer consumer = null; + + LOG.info("Publisher will publish " + (publisherMessagesPerThread * publisherThreadCount) + " messages to each queue specified."); + LOG.info("\nBuilding Publisher..."); + + publisher = new ExportQueuePublisher(activemqURL, activemqQueues, publisherMessagesPerThread, publisherThreadCount); + + LOG.info("Building Consumer..."); + + consumer = new ExportQueueConsumer(activemqURL, activemqQueues, consumerThreadsPerQueue, consumerBatchSize, publisherMessagesPerThread * publisherThreadCount); + + + LOG.info("Starting Publisher..."); + + publisher.start(); + + LOG.info("Starting Consumer..."); + + consumer.start(); + + int distinctPublishedCount = 0; + + + LOG.info("Waiting For Publisher Completion..."); + + publisher.waitForCompletion(); + + List publishedIds = publisher.getIDs(); + distinctPublishedCount = new TreeSet(publishedIds).size(); + + LOG.info("Publisher Complete. Published: " + publishedIds.size() + ", Distinct IDs Published: " + distinctPublishedCount); + + + long endWait = System.currentTimeMillis() + consumerWaitForConsumption; + while (!consumer.completed() && System.currentTimeMillis() < endWait) { + try { + int secs = (int) (endWait - System.currentTimeMillis()) / 1000; + LOG.info("Waiting For Consumer Completion. Time left: " + secs + " secs"); + Thread.sleep(10000); + } catch (Exception e) { + } + } + + LOG.info("\nConsumer Complete: " + consumer.completed() +", Shutting Down."); + + consumer.shutdown(); + + LOG.info("Consumer Stats:"); + + for (Map.Entry> entry : consumer.getIDs().entrySet()) { + + List idList = entry.getValue(); + + int distinctConsumed = new TreeSet(idList).size(); + + StringBuilder sb = new StringBuilder(); + sb.append(" Queue: " + entry.getKey() + + " -> Total Messages Consumed: " + idList.size() + + ", Distinct IDs Consumed: " + distinctConsumed); + + int diff = distinctPublishedCount - distinctConsumed; + sb.append(" ( " + (diff > 0 ? diff : "NO") + " STUCK MESSAGES " + " ) "); + LOG.info(sb.toString()); + + assertEquals("expect to get all messages!", 0, diff); + + } + } + + public class ExportQueuePublisher { + + private final String amqUser = ActiveMQConnection.DEFAULT_USER; + private final String amqPassword = ActiveMQConnection.DEFAULT_PASSWORD; + private ActiveMQConnectionFactory connectionFactory = null; + private String activemqURL = null; + private String activemqQueues = null; + // Collection of distinct IDs that the publisher has published. + // After a message is published, its UUID will be written to this list for tracking. + // This list of IDs (or distinct count) will be used to compare to the consumed list of IDs. + //private Set ids = Collections.synchronizedSet(new TreeSet()); + private List ids = Collections.synchronizedList(new ArrayList()); + private List threads; + + public ExportQueuePublisher(String activemqURL, String activemqQueues, int messagesPerThread, int threadCount) throws Exception { + + this.activemqURL = activemqURL; + this.activemqQueues = activemqQueues; + + threads = new ArrayList(); + + // Build the threads and tell them how many messages to publish + for (int i = 0; i < threadCount; i++) { + PublisherThread pt = new PublisherThread(messagesPerThread); + threads.add(pt); + } + } + + public List getIDs() { + return ids; + } + + // Kick off threads + public void start() throws Exception { + + for (PublisherThread pt : threads) { + pt.start(); + } + } + + // Wait for threads to complete. They will complete once they've published all of their messages. + public void waitForCompletion() throws Exception { + + for (PublisherThread pt : threads) { + pt.join(); + pt.close(); + } + } + + private Session newSession(QueueConnection queueConnection) throws Exception { + return queueConnection.createSession(true, Session.SESSION_TRANSACTED); + } + + private synchronized QueueConnection newQueueConnection() throws Exception { + + if (connectionFactory == null) { + connectionFactory = new ActiveMQConnectionFactory(amqUser, amqPassword, activemqURL); + } + + // Set the redelivery count to -1 (infinite), or else messages will start dropping + // after the queue has had a certain number of failures (default is 6) + RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy(); + policy.setMaximumRedeliveries(-1); + + QueueConnection amqConnection = connectionFactory.createQueueConnection(); + amqConnection.start(); + return amqConnection; + } + + private class PublisherThread extends Thread { + + private int count; + private QueueConnection qc; + private Session session; + private MessageProducer mp; + + private PublisherThread(int count) throws Exception { + + this.count = count; + + // Each Thread has its own Connection and Session, so no sync worries + qc = newQueueConnection(); + session = newSession(qc); + + // In our code, when publishing to multiple queues, + // we're using composite destinations like below + Queue q = new ActiveMQQueue(activemqQueues); + mp = session.createProducer(q); + } + + public void run() { + + try { + + // Loop until we've published enough messages + while (count-- > 0) { + + TextMessage tm = session.createTextMessage(getMessageText()); + String id = UUID.randomUUID().toString(); + tm.setStringProperty("KEY", id); + ids.add(id); // keep track of the key to compare against consumer + + mp.send(tm); + session.commit(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // Called by waitForCompletion + public void close() { + + try { + mp.close(); + } catch (Exception e) { + } + + try { + session.close(); + } catch (Exception e) { + } + + try { + qc.close(); + } catch (Exception e) { + } + } + } + + } + + String messageText; + private String getMessageText() { + + if (messageText == null) { + + synchronized (this) { + + if (messageText == null) { + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < messageSize; i++) { + sb.append("X"); + } + messageText = sb.toString(); + } + } + } + + return messageText; + } + + + public class ExportQueueConsumer { + + private final String amqUser = ActiveMQConnection.DEFAULT_USER; + private final String amqPassword = ActiveMQConnection.DEFAULT_PASSWORD; + private final int totalToExpect; + private ActiveMQConnectionFactory connectionFactory = null; + private String activemqURL = null; + private String activemqQueues = null; + private String[] queues = null; + // Map of IDs that were consumed, keyed by queue name. + // We'll compare these against what was published to know if any got stuck or dropped. + private Map> idsByQueue = new HashMap>(); + private Map> threads; + + public ExportQueueConsumer(String activemqURL, String activemqQueues, int threadsPerQueue, int batchSize, int totalToExpect) throws Exception { + + this.activemqURL = activemqURL; + this.activemqQueues = activemqQueues; + this.totalToExpect = totalToExpect; + + queues = this.activemqQueues.split(","); + + for (int i = 0; i < queues.length; i++) { + queues[i] = queues[i].trim(); + } + + threads = new HashMap>(); + + // For each queue, create a list of threads and set up the list of ids + for (String q : queues) { + + List list = new ArrayList(); + + idsByQueue.put(q, Collections.synchronizedList(new ArrayList())); + + for (int i = 0; i < threadsPerQueue; i++) { + list.add(new ConsumerThread(q, batchSize)); + } + + threads.put(q, list); + } + } + + public Map> getIDs() { + return idsByQueue; + } + + // Start the threads + public void start() throws Exception { + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.start(); + } + } + } + + // Tell the threads to stop + // Then wait for them to stop + public void shutdown() throws Exception { + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.shutdown(); + } + } + + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + ct.join(); + } + } + } + + private Session newSession(QueueConnection queueConnection) throws Exception { + return queueConnection.createSession(true, Session.SESSION_TRANSACTED); + } + + private synchronized QueueConnection newQueueConnection() throws Exception { + + if (connectionFactory == null) { + connectionFactory = new ActiveMQConnectionFactory(amqUser, amqPassword, activemqURL); + } + + // Set the redelivery count to -1 (infinite), or else messages will start dropping + // after the queue has had a certain number of failures (default is 6) + RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy(); + policy.setMaximumRedeliveries(-1); + + QueueConnection amqConnection = connectionFactory.createQueueConnection(); + amqConnection.start(); + return amqConnection; + } + + public boolean completed() { + for (List list : threads.values()) { + + for (ConsumerThread ct : list) { + + if (ct.isAlive()) { + LOG.info("thread for {} is still alive.", ct.qName); + return false; + } + } + } + return true; + } + + private class ConsumerThread extends Thread { + + private int batchSize; + private QueueConnection qc; + private Session session; + private MessageConsumer mc; + private List idList; + private boolean shutdown = false; + private String qName; + + private ConsumerThread(String queueName, int batchSize) throws Exception { + + this.batchSize = batchSize; + + // Each thread has its own connection and session + qName = queueName; + qc = newQueueConnection(); + session = newSession(qc); + Queue q = session.createQueue(queueName + "?consumer.prefetchSize=" + batchSize); + mc = session.createConsumer(q); + + idList = idsByQueue.get(queueName); + } + + public void run() { + + try { + + int count = 0; + + // Keep reading as long as it hasn't been told to shutdown + while (!shutdown) { + + if (idList.size() >= totalToExpect) { + LOG.info("Got {} for q: {}", +idList.size(), qName); + session.commit(); + break; + } + Message m = mc.receive(4000); + + if (m != null) { + + // We received a non-null message, add the ID to our list + + idList.add(m.getStringProperty("KEY")); + + count++; + + // If we've reached our batch size, commit the batch and reset the count + + if (count == batchSize) { + session.commit(); + count = 0; + } + } else { + + // We didn't receive anything this time, commit any current batch and reset the count + + session.commit(); + count = 0; + + // Sleep a little before trying to read after not getting a message + + try { + if (idList.size() < totalToExpect) { + LOG.info("did not receive on {}, current count: {}", qName, idList.size()); + } + //sleep(3000); + } catch (Exception e) { + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + + // Once we exit, close everything + close(); + } + } + + public void shutdown() { + shutdown = true; + } + + public void close() { + + try { + mc.close(); + } catch (Exception e) { + } + + try { + session.close(); + } catch (Exception e) { + } + + try { + qc.close(); + } catch (Exception e) { + + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5274Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5274Test.java new file mode 100644 index 0000000000..4ba6526890 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5274Test.java @@ -0,0 +1,133 @@ +/** + * 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.bugs; + +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerMBeanSupport; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class AMQ5274Test { + static Logger LOG = LoggerFactory.getLogger(AMQ5274Test.class); + String activemqURL; + BrokerService brokerService; + ActiveMQQueue dest = new ActiveMQQueue("TestQ"); + + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setExpireMessagesPeriod(1000); + policyMap.setDefaultEntry(defaultPolicy); + brokerService.setDestinationPolicy(policyMap); + activemqURL = brokerService.addConnector("tcp://localhost:0").getPublishableConnectString(); + brokerService.start(); + } + + @After + public void stopBroker() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + @Test + public void test() throws Exception { + LOG.info("Starting Test"); + assertTrue(brokerService.isStarted()); + + produce(); + consumeAndRollback(); + + // check reported queue size using JMX + long queueSize = getQueueSize(); + assertEquals("Queue " + dest.getPhysicalName() + " not empty, reporting " + queueSize + " messages.", 0, queueSize); + } + + private void consumeAndRollback() throws JMSException, InterruptedException { + ActiveMQConnection connection = createConnection(); + RedeliveryPolicy noRedelivery = new RedeliveryPolicy(); + noRedelivery.setMaximumRedeliveries(0); + connection.setRedeliveryPolicy(noRedelivery); + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(dest); + Message m; + while ( (m = consumer.receive(4000)) != null) { + LOG.info("Got:" + m); + TimeUnit.SECONDS.sleep(1); + session.rollback(); + } + connection.close(); + } + + private void produce() throws Exception { + Connection connection = createConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(dest); + producer.setTimeToLive(10000); + for (int i=0;i<20;i++) { + producer.send(session.createTextMessage("i="+i)); + } + connection.close(); + } + + private ActiveMQConnection createConnection() throws JMSException { + return (ActiveMQConnection) new ActiveMQConnectionFactory(activemqURL).createConnection(); + } + + + public long getQueueSize() throws Exception { + long queueSize = 0; + try { + QueueViewMBean queueViewMBean = (QueueViewMBean) brokerService.getManagementContext().newProxyInstance(BrokerMBeanSupport.createDestinationName(brokerService.getBrokerObjectName(), dest), QueueViewMBean.class, false); + queueSize = queueViewMBean.getQueueSize(); + LOG.info("QueueSize for destination {} is {}", dest, queueSize); + } catch (Exception ex) { + LOG.error("Error retrieving QueueSize from JMX ", ex); + throw ex; + } + return queueSize; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5381Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5381Test.java new file mode 100644 index 0000000000..ff10b0dd36 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5381Test.java @@ -0,0 +1,182 @@ +/** + * 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.bugs; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Random; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQBytesMessage; +import org.apache.activemq.command.ActiveMQMessage; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class AMQ5381Test { + + public static final byte[] ORIG_MSG_CONTENT = randomByteArray(); + public static final String AMQ5381_EXCEPTION_MESSAGE = "java.util.zip.DataFormatException: incorrect header check"; + + private BrokerService brokerService; + private String brokerURI; + + @Rule public TestName name = new TestName(); + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(false); + brokerService.addConnector("tcp://localhost:0"); + brokerService.start(); + brokerService.waitUntilStarted(); + + brokerURI = brokerService.getTransportConnectorByScheme("tcp").getPublishableConnectString(); + } + + @After + public void stopBroker() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + private ActiveMQConnection createConnection(boolean useCompression) throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI); + factory.setUseCompression(useCompression); + Connection connection = factory.createConnection(); + connection.start(); + return (ActiveMQConnection) connection; + } + + @Test + public void amq5381Test() throws Exception { + + // Consumer Configured for (useCompression=true) + final ActiveMQConnection consumerConnection = createConnection(true); + final Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue consumerQueue = consumerSession.createQueue(name.getMethodName()); + final MessageConsumer consumer = consumerSession.createConsumer(consumerQueue); + + // Producer Configured for (useCompression=false) + final ActiveMQConnection producerConnection = createConnection(false); + final Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue producerQueue = producerSession.createQueue(name.getMethodName()); + + try { + + final ActiveMQBytesMessage messageProduced = (ActiveMQBytesMessage) producerSession.createBytesMessage(); + messageProduced.writeBytes(ORIG_MSG_CONTENT); + Assert.assertFalse(messageProduced.isReadOnlyBody()); + + Assert.assertFalse( + "Produced Message's 'compressed' flag should remain false until the message is sent (where it will be compressed, if necessary)", + messageProduced.isCompressed()); + + final MessageProducer producer = producerSession.createProducer(null); + producer.send(producerQueue, messageProduced); + + Assert.assertEquals("Once sent, the produced Message's 'compressed' flag should match its Connection's 'useCompression' flag", + producerConnection.isUseCompression(), messageProduced.isCompressed()); + + final ActiveMQBytesMessage messageConsumed = (ActiveMQBytesMessage) consumer.receive(); + Assert.assertNotNull(messageConsumed); + Assert.assertTrue("Consumed Message should be read-only", messageConsumed.isReadOnlyBody()); + Assert.assertEquals("Consumed Message's 'compressed' flag should match the produced Message's 'compressed' flag", + messageProduced.isCompressed(), messageConsumed.isCompressed()); + + // ensure consumed message content matches what was originally set + final byte[] consumedMsgContent = new byte[(int) messageConsumed.getBodyLength()]; + messageConsumed.readBytes(consumedMsgContent); + + Assert.assertTrue("Consumed Message content should match the original Message content", Arrays.equals(ORIG_MSG_CONTENT, consumedMsgContent)); + + // make message writable so the consumer can modify and reuse it + makeWritable(messageConsumed); + + // modify message, attempt to trigger DataFormatException due + // to old incorrect compression logic + try { + messageConsumed.setStringProperty(this.getClass().getName(), "test"); + } catch (JMSException jmsE) { + if (AMQ5381_EXCEPTION_MESSAGE.equals(jmsE.getMessage())) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + jmsE.printStackTrace(pw); + + Assert.fail("AMQ5381 Error State Achieved: attempted to decompress BytesMessage contents that are not compressed\n" + sw.toString()); + } else { + throw jmsE; + } + } + + Assert.assertEquals( + "The consumed Message's 'compressed' flag should still match the produced Message's 'compressed' flag after it has been made writable", + messageProduced.isCompressed(), messageConsumed.isCompressed()); + + // simulate re-publishing message + simulatePublish(messageConsumed); + + // ensure consumed message content matches what was originally set + final byte[] modifiedMsgContent = new byte[(int) messageConsumed.getBodyLength()]; + messageConsumed.readBytes(modifiedMsgContent); + + Assert.assertTrue( + "After the message properties are modified and it is re-published, its message content should still match the original message content", + Arrays.equals(ORIG_MSG_CONTENT, modifiedMsgContent)); + } finally { + producerSession.close(); + producerConnection.close(); + consumerSession.close(); + consumerConnection.close(); + } + } + + protected static final int MAX_RANDOM_BYTE_ARRAY_SIZE_KB = 128; + + protected static byte[] randomByteArray() { + final Random random = new Random(); + final byte[] byteArray = new byte[random.nextInt(MAX_RANDOM_BYTE_ARRAY_SIZE_KB * 1024)]; + random.nextBytes(byteArray); + + return byteArray; + } + + protected static void makeWritable(final ActiveMQMessage message) { + message.setReadOnlyBody(false); + message.setReadOnlyProperties(false); + } + + protected static void simulatePublish(final ActiveMQBytesMessage message) throws JMSException { + message.reset(); + message.onSend(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5421Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5421Test.java new file mode 100644 index 0000000000..751d488214 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5421Test.java @@ -0,0 +1,119 @@ +/** + * 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.bugs; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.AbortSlowAckConsumerStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ5421Test { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ5421Test.class); + + private static final int DEST_COUNT = 1000; + private final Destination[] destination = new Destination[DEST_COUNT]; + private final MessageProducer[] producer = new MessageProducer[DEST_COUNT]; + private BrokerService brokerService; + private String connectionUri; + + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory conFactory = new ActiveMQConnectionFactory(connectionUri); + conFactory.setWatchTopicAdvisories(false); + return conFactory; + } + + protected AbortSlowAckConsumerStrategy createSlowConsumerStrategy() { + AbortSlowAckConsumerStrategy strategy = new AbortSlowAckConsumerStrategy(); + strategy.setCheckPeriod(2000); + strategy.setMaxTimeSinceLastAck(5000); + strategy.setIgnoreIdleConsumers(false); + + return strategy; + } + + @Before + public void setUp() throws Exception { + brokerService = BrokerFactory.createBroker(new URI("broker://()/localhost?persistent=false&useJmx=true")); + PolicyEntry policy = new PolicyEntry(); + + policy.setSlowConsumerStrategy(createSlowConsumerStrategy()); + policy.setQueuePrefetch(10); + policy.setTopicPrefetch(10); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + brokerService.setDestinationPolicy(pMap); + brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.start(); + + connectionUri = brokerService.getTransportConnectorByScheme("tcp").getPublishableConnectString(); + } + + @Test + public void testManyTempDestinations() throws Exception { + Connection connection = createConnectionFactory().createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + for (int i = 0; i < DEST_COUNT; i++) { + destination[i] = session.createTemporaryQueue(); + LOG.debug("Created temp queue: [}", i); + } + + for (int i = 0; i < DEST_COUNT; i++) { + producer[i] = session.createProducer(destination[i]); + LOG.debug("Created producer: {}", i); + TextMessage msg = session.createTextMessage(" testMessage " + i); + producer[i].send(msg); + LOG.debug("message sent: {}", i); + MessageConsumer consumer = session.createConsumer(destination[i]); + Message message = consumer.receive(1000); + Assert.assertTrue(message.equals(msg)); + } + + for (int i = 0; i < DEST_COUNT; i++) { + producer[i].close(); + } + + connection.close(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5450Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5450Test.java new file mode 100644 index 0000000000..6a2dc52c07 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5450Test.java @@ -0,0 +1,194 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.*; + +public class AMQ5450Test { + + static final Logger LOG = LoggerFactory.getLogger(AMQ5450Test.class); + private final static int maxFileLength = 1024*1024*32; + + private final static String POSTFIX_DESTINATION_NAME = ".dlq"; + + private final static String DESTINATION_NAME = "test" + POSTFIX_DESTINATION_NAME; + private final static String DESTINATION_NAME_2 = "2.test" + POSTFIX_DESTINATION_NAME; + private final static String DESTINATION_NAME_3 = "3.2.test" + POSTFIX_DESTINATION_NAME; + + private final static String[] DESTS = new String[] {DESTINATION_NAME, DESTINATION_NAME_2, DESTINATION_NAME_3, DESTINATION_NAME, DESTINATION_NAME}; + + + BrokerService broker; + private HashMap adapters = new HashMap(); + + @After + public void tearDown() throws Exception { + broker.stop(); + } + + protected BrokerService createAndStartBroker(PersistenceAdapter persistenceAdapter) throws Exception { + BrokerService broker = new BrokerService(); + broker.setUseJmx(false); + broker.setBrokerName("localhost"); + broker.setPersistenceAdapter(persistenceAdapter); + broker.setDeleteAllMessagesOnStartup(true); + broker.start(); + broker.waitUntilStarted(); + return broker; + } + + @Test + public void testPostFixMatch() throws Exception { + doTestPostFixMatch(false); + } + + @Test + public void testPostFixCompositeMatch() throws Exception { + doTestPostFixMatch(true); + } + + private void doTestPostFixMatch(boolean useComposite) throws Exception { + prepareBrokerWithMultiStore(useComposite); + + sendMessage(DESTINATION_NAME, "test 1"); + sendMessage(DESTINATION_NAME_2, "test 1"); + sendMessage(DESTINATION_NAME_3, "test 1"); + + assertNotNull(broker.getDestination(new ActiveMQQueue(DESTINATION_NAME))); + assertNotNull(broker.getDestination(new ActiveMQQueue(DESTINATION_NAME_2))); + assertNotNull(broker.getDestination(new ActiveMQQueue(DESTINATION_NAME_3))); + + for (String dest: DESTS) { + Destination destination2 = broker.getDestination(new ActiveMQQueue(dest)); + assertNotNull(destination2); + assertEquals(1, destination2.getMessageStore().getMessageCount()); + } + + HashMap numDests = new HashMap(); + for (PersistenceAdapter pa : adapters.values()) { + numDests.put(pa.getDestinations().size(), pa); + } + + // ensure wildcard does not match any + assertTrue("0 in wildcard matcher", adapters.get(null).getDestinations().isEmpty()); + + assertEquals("only two values", 2, numDests.size()); + assertTrue("0 in others", numDests.containsKey(0)); + + if (useComposite) { + assertTrue("3 in one", numDests.containsKey(3)); + } else { + assertTrue("1 in some", numDests.containsKey(1)); + } + + } + + protected KahaDBPersistenceAdapter createStore(boolean delete) throws IOException { + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setJournalMaxFileLength(maxFileLength); + kaha.setCleanupInterval(5000); + if (delete) { + kaha.deleteAllMessages(); + } + return kaha; + } + + public void prepareBrokerWithMultiStore(boolean compositeMatch) throws Exception { + + MultiKahaDBPersistenceAdapter multiKahaDBPersistenceAdapter = new MultiKahaDBPersistenceAdapter(); + multiKahaDBPersistenceAdapter.deleteAllMessages(); + ArrayList adapters = new ArrayList(); + + if (compositeMatch) { + StringBuffer compositeDestBuf = new StringBuffer(); + for (int i=1; i<=DESTS.length;i++) { + for (int j=0;j DESTS.length)) { + compositeDestBuf.append(","); + } + } + adapters.add(createFilteredKahaDBByDestinationPrefix(compositeDestBuf.toString(), true)); + + } else { + // destination map does not do post fix wild card matches on paths, so we need to cover + // each path length + adapters.add(createFilteredKahaDBByDestinationPrefix("*" + POSTFIX_DESTINATION_NAME, true)); + adapters.add(createFilteredKahaDBByDestinationPrefix("*.*" + POSTFIX_DESTINATION_NAME, true)); + adapters.add(createFilteredKahaDBByDestinationPrefix("*.*.*" + POSTFIX_DESTINATION_NAME, true)); + adapters.add(createFilteredKahaDBByDestinationPrefix("*.*.*.*" + POSTFIX_DESTINATION_NAME, true)); + } + + // ensure wildcard matcher is there for other dests + adapters.add(createFilteredKahaDBByDestinationPrefix(null, true)); + + multiKahaDBPersistenceAdapter.setFilteredPersistenceAdapters(adapters); + broker = createAndStartBroker(multiKahaDBPersistenceAdapter); + } + + private FilteredKahaDBPersistenceAdapter createFilteredKahaDBByDestinationPrefix(String destinationPrefix, boolean deleteAllMessages) + throws IOException { + FilteredKahaDBPersistenceAdapter template = new FilteredKahaDBPersistenceAdapter(); + template.setPersistenceAdapter(createStore(deleteAllMessages)); + if (destinationPrefix != null) { + template.setQueue(destinationPrefix); + } + adapters.put(destinationPrefix, template.getPersistenceAdapter()); + return template; + } + + private void sendMessage(String destinationName, String message) throws JMSException { + ActiveMQConnectionFactory f = new ActiveMQConnectionFactory("vm://localhost"); + f.setAlwaysSyncSend(true); + Connection c = f.createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = s.createProducer(new ActiveMQQueue(destinationName)); + producer.send(s.createTextMessage(message)); + producer.close(); + s.close(); + c.stop(); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5567Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5567Test.java new file mode 100644 index 0000000000..a8739ae2da --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ5567Test.java @@ -0,0 +1,228 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.concurrent.TimeUnit; +import javax.jms.JMSException; +import javax.jms.TextMessage; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import junit.framework.Test; +import org.apache.activemq.broker.BrokerRestartTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.command.XATransactionId; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.leveldb.LevelDBPersistenceAdapter; +import org.apache.activemq.util.IOHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AMQ5567Test extends BrokerRestartTestSupport { + protected static final Logger LOG = LoggerFactory.getLogger(AMQ5567Test.class); + ActiveMQQueue destination = new ActiveMQQueue("Q"); + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + super.configureBroker(broker); + broker.setPersistenceAdapter(persistenceAdapter); + } + + protected PolicyEntry getDefaultPolicy() { + PolicyEntry policy = new PolicyEntry(); + policy.setMemoryLimit(60*1024); + return policy; + } + + public void initCombosForTestPreparedTransactionNotDispatched() throws Exception { + PersistenceAdapter[] persistenceAdapters = new PersistenceAdapter[]{ + new KahaDBPersistenceAdapter(), + new LevelDBPersistenceAdapter(), + new JDBCPersistenceAdapter(JDBCPersistenceAdapter.createDataSource(IOHelper.getDefaultDataDirectory()), new OpenWireFormat()) + }; + for (PersistenceAdapter adapter : persistenceAdapters) { + adapter.setDirectory(new File(IOHelper.getDefaultDataDirectory())); + } + addCombinationValues("persistenceAdapter", persistenceAdapters); + } + + public void testPreparedTransactionNotDispatched() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("Q"); + + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.send(message); + + connection.send(createPrepareTransaction(connectionInfo, txid)); + + + // send another non tx, will poke dispatch + message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + + + // Since prepared but not committed.. only one should get delivered + StubConnection connectionC = createConnection(); + ConnectionInfo connectionInfoC = createConnectionInfo(); + SessionInfo sessionInfoC = createSessionInfo(connectionInfoC); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfoC, destination); + connectionC.send(connectionInfoC); + connectionC.send(sessionInfoC); + connectionC.send(consumerInfo); + + Message m = receiveMessage(connectionC, TimeUnit.SECONDS.toMillis(10)); + LOG.info("received: " + m); + assertNotNull("Got message", m); + assertNull("Got non tx message", m.getTransactionId()); + + // cannot get the prepared message till commit + assertNull(receiveMessage(connectionC)); + assertNoMessagesLeft(connectionC); + + LOG.info("commit: " + txid); + connection.request(createCommitTransaction2Phase(connectionInfo, txid)); + + m = receiveMessage(connectionC, TimeUnit.SECONDS.toMillis(10)); + LOG.info("received: " + m); + assertNotNull("Got non null message", m); + + } + + public void initCombosForTestCursorStoreSync() throws Exception { + PersistenceAdapter[] persistenceAdapters = new PersistenceAdapter[]{ + new KahaDBPersistenceAdapter(), + new LevelDBPersistenceAdapter(), + new JDBCPersistenceAdapter(JDBCPersistenceAdapter.createDataSource(IOHelper.getDefaultDataDirectory()), new OpenWireFormat()) + }; + for (PersistenceAdapter adapter : persistenceAdapters) { + adapter.setDirectory(new File(IOHelper.getDefaultDataDirectory())); + } + addCombinationValues("persistenceAdapter", persistenceAdapters); + } + + public void testCursorStoreSync() throws Exception { + + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + + XATransactionId txid = createXATransaction(sessionInfo); + connection.send(createBeginTransaction(connectionInfo, txid)); + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + message.setTransactionId(txid); + connection.request(message); + + connection.request(createPrepareTransaction(connectionInfo, txid)); + + QueueViewMBean proxy = getProxyToQueueViewMBean(); + assertTrue("cache is enabled", proxy.isCacheEnabled()); + + // send another non tx, will fill cursor + String payload = new String(new byte[10*1024]); + for (int i=0; i<6; i++) { + message = createMessage(producerInfo, destination); + message.setPersistent(true); + ((TextMessage)message).setText(payload); + connection.request(message); + } + + assertTrue("cache is disabled", !proxy.isCacheEnabled()); + + StubConnection connectionC = createConnection(); + ConnectionInfo connectionInfoC = createConnectionInfo(); + SessionInfo sessionInfoC = createSessionInfo(connectionInfoC); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfoC, destination); + connectionC.send(connectionInfoC); + connectionC.send(sessionInfoC); + connectionC.send(consumerInfo); + + Message m = null; + for (int i=0; i<3; i++) { + m = receiveMessage(connectionC, TimeUnit.SECONDS.toMillis(10)); + LOG.info("received: " + m); + assertNotNull("Got message", m); + assertNull("Got non tx message", m.getTransactionId()); + connectionC.request(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + } + + LOG.info("commit: " + txid); + connection.request(createCommitTransaction2Phase(connectionInfo, txid)); + // consume the rest including the 2pc send in TX + + for (int i=0; i<4; i++) { + m = receiveMessage(connectionC, TimeUnit.SECONDS.toMillis(10)); + LOG.info("received[" + i + "] " + m); + assertNotNull("Got message", m); + if (i==3 ) { + assertNotNull("Got tx message", m.getTransactionId()); + } else { + assertNull("Got non tx message", m.getTransactionId()); + } + connectionC.request(createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE)); + } + } + + private QueueViewMBean getProxyToQueueViewMBean() + throws MalformedObjectNameException, JMSException { + ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq" + + ":destinationType=Queue,destinationName=" + destination.getQueueName() + + ",type=Broker,brokerName=localhost"); + QueueViewMBean proxy = (QueueViewMBean) broker.getManagementContext() + .newProxyInstance(queueViewMBeanName, + QueueViewMBean.class, true); + return proxy; + } + + public static Test suite() { + return suite(AMQ5567Test.class); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/ActiveMQSlowConsumerManualTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/ActiveMQSlowConsumerManualTest.java new file mode 100644 index 0000000000..b32c7ad8ba --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/ActiveMQSlowConsumerManualTest.java @@ -0,0 +1,232 @@ +/** + * 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.bugs; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.ConstantPendingMessageLimitStrategy; +import org.apache.activemq.broker.region.policy.OldestMessageEvictionStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author James Furness + * https://issues.apache.org/jira/browse/AMQ-3607 + */ +public class ActiveMQSlowConsumerManualTest { + private static final int PORT = 12345; + private static final ActiveMQTopic TOPIC = new ActiveMQTopic("TOPIC"); + private static final String URL = "nio://localhost:" + PORT + "?socket.tcpNoDelay=true"; + + @Test(timeout = 60000) + public void testDefaultSettings() throws Exception { + runTest("testDefaultSettings", 30, -1, -1, false, false, false, false); + } + + @Test(timeout = 60000) + public void testDefaultSettingsWithOptimiseAcknowledge() throws Exception { + runTest("testDefaultSettingsWithOptimiseAcknowledge", 30, -1, -1, false, false, true, false); + } + + @Test(timeout = 60000) + public void testBounded() throws Exception { + runTest("testBounded", 30, 5, 25, false, false, false, false); + } + + @Test(timeout = 60000) + public void testBoundedWithOptimiseAcknowledge() throws Exception { + runTest("testBoundedWithOptimiseAcknowledge", 30, 5, 25, false, false, true, false); + } + + public void runTest(String name, int sendMessageCount, int prefetchLimit, int messageLimit, boolean evictOldestMessage, boolean disableFlowControl, boolean optimizeAcknowledge, boolean persistent) throws Exception { + BrokerService broker = createBroker(persistent); + broker.setDestinationPolicy(buildPolicy(TOPIC, prefetchLimit, messageLimit, evictOldestMessage, disableFlowControl)); + broker.start(); + + // Slow consumer + Session slowConsumerSession = buildSession("SlowConsumer", URL, optimizeAcknowledge); + final CountDownLatch blockSlowConsumer = new CountDownLatch(1); + final AtomicInteger slowConsumerReceiveCount = new AtomicInteger(); + final List slowConsumerReceived = sendMessageCount <= 1000 ? new ArrayList() : null; + MessageConsumer slowConsumer = createSubscriber(slowConsumerSession, + new MessageListener() { + @Override + public void onMessage(Message message) { + try { + slowConsumerReceiveCount.incrementAndGet(); + int count = Integer.parseInt(((TextMessage) message).getText()); + if (slowConsumerReceived != null) slowConsumerReceived.add(count); + if (count % 10000 == 0) System.out.println("SlowConsumer: Receive " + count); + blockSlowConsumer.await(); + } catch (Exception ignored) { + } + } + } + ); + + // Fast consumer + Session fastConsumerSession = buildSession("FastConsumer", URL, optimizeAcknowledge); + final AtomicInteger fastConsumerReceiveCount = new AtomicInteger(); + final List fastConsumerReceived = sendMessageCount <= 1000 ? new ArrayList() : null; + MessageConsumer fastConsumer = createSubscriber(fastConsumerSession, + new MessageListener() { + @Override + public void onMessage(Message message) { + try { + fastConsumerReceiveCount.incrementAndGet(); + TimeUnit.MILLISECONDS.sleep(5); + int count = Integer.parseInt(((TextMessage) message).getText()); + if (fastConsumerReceived != null) fastConsumerReceived.add(count); + if (count % 10000 == 0) System.out.println("FastConsumer: Receive " + count); + } catch (Exception ignored) { + } + } + } + ); + + // Wait for consumers to connect + Thread.sleep(500); + + // Publisher + AtomicInteger sentCount = new AtomicInteger(); + List sent = sendMessageCount <= 1000 ? new ArrayList() : null; + Session publisherSession = buildSession("Publisher", URL, optimizeAcknowledge); + MessageProducer publisher = createPublisher(publisherSession); + for (int i = 0; i < sendMessageCount; i++) { + sentCount.incrementAndGet(); + if (sent != null) sent.add(i); + if (i % 10000 == 0) System.out.println("Publisher: Send " + i); + publisher.send(publisherSession.createTextMessage(Integer.toString(i))); + } + + // Wait for messages to arrive + Thread.sleep(500); + + System.out.println(name + ": Publisher Sent: " + sentCount + " " + sent); + System.out.println(name + ": Whilst slow consumer blocked:"); + System.out.println("\t\t- SlowConsumer Received: " + slowConsumerReceiveCount + " " + slowConsumerReceived); + System.out.println("\t\t- FastConsumer Received: " + fastConsumerReceiveCount + " " + fastConsumerReceived); + + // Unblock slow consumer + blockSlowConsumer.countDown(); + + // Wait for messages to arrive + Thread.sleep(500); + + System.out.println(name + ": After slow consumer unblocked:"); + System.out.println("\t\t- SlowConsumer Received: " + slowConsumerReceiveCount + " " + slowConsumerReceived); + System.out.println("\t\t- FastConsumer Received: " + fastConsumerReceiveCount + " " + fastConsumerReceived); + System.out.println(); + + publisher.close(); + publisherSession.close(); + slowConsumer.close(); + slowConsumerSession.close(); + fastConsumer.close(); + fastConsumerSession.close(); + broker.stop(); + + Assert.assertEquals("Fast consumer missed messages whilst slow consumer was blocking", sent, fastConsumerReceived); + // this is too timine dependent as sometimes there is message eviction, would need to check the dlq + //Assert.assertEquals("Slow consumer received incorrect message count", Math.min(sendMessageCount, prefetchLimit + (messageLimit > 0 ? messageLimit : Integer.MAX_VALUE)), slowConsumerReceived.size()); + } + + private static BrokerService createBroker(boolean persistent) throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("TestBroker"); + broker.setPersistent(persistent); + broker.addConnector(URL); + return broker; + } + + private static MessageConsumer createSubscriber(Session session, MessageListener messageListener) throws JMSException { + MessageConsumer consumer = session.createConsumer(TOPIC); + consumer.setMessageListener(messageListener); + return consumer; + } + + private static MessageProducer createPublisher(Session session) throws JMSException { + MessageProducer producer = session.createProducer(TOPIC); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + return producer; + } + + private static Session buildSession(String clientId, String url, boolean optimizeAcknowledge) throws JMSException { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url); + + connectionFactory.setCopyMessageOnSend(false); + connectionFactory.setDisableTimeStampsByDefault(true); + connectionFactory.setOptimizeAcknowledge(optimizeAcknowledge); + if (optimizeAcknowledge) { + connectionFactory.setOptimizeAcknowledgeTimeOut(1); + } + + Connection connection = connectionFactory.createConnection(); + connection.setClientID(clientId); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + connection.start(); + + return session; + } + + private static PolicyMap buildPolicy(ActiveMQTopic topic, int prefetchLimit, int messageLimit, boolean evictOldestMessage, boolean disableFlowControl) { + PolicyMap policyMap = new PolicyMap(); + + PolicyEntry policyEntry = new PolicyEntry(); + + if (evictOldestMessage) { + policyEntry.setMessageEvictionStrategy(new OldestMessageEvictionStrategy()); + } + + if (disableFlowControl) { + policyEntry.setProducerFlowControl(false); + } + + if (prefetchLimit > 0) { + policyEntry.setTopicPrefetch(prefetchLimit); + } + + if (messageLimit > 0) { + ConstantPendingMessageLimitStrategy messageLimitStrategy = new ConstantPendingMessageLimitStrategy(); + messageLimitStrategy.setLimit(messageLimit); + policyEntry.setPendingMessageLimitStrategy(messageLimitStrategy); + } + + policyMap.put(topic, policyEntry); + + return policyMap; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/ConnectionPerMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/ConnectionPerMessageTest.java new file mode 100644 index 0000000000..8c580a9bc1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/ConnectionPerMessageTest.java @@ -0,0 +1,104 @@ +/** + * 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.bugs; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConnectionPerMessageTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(ConnectionPerMessageTest.class); + private static final int COUNT = 2000; + protected String bindAddress; + + public void testConnectionPerMessage() throws Exception { + final String topicName = "test.topic"; + + LOG.info("Initializing connection factory for JMS to URL: " + + bindAddress); + final ActiveMQConnectionFactory normalFactory = new ActiveMQConnectionFactory(); + normalFactory.setBrokerURL(bindAddress); + for (int i = 0; i < COUNT; i++) { + + if (i % 100 == 0) { + LOG.info(new Integer(i).toString()); + } + + Connection conn = null; + try { + + conn = normalFactory.createConnection(); + final Session session = conn.createSession(false, + Session.AUTO_ACKNOWLEDGE); + final Topic topic = session.createTopic(topicName); + final MessageProducer producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + final MapMessage m = session.createMapMessage(); + m.setInt("hey", i); + + producer.send(m); + + } catch (JMSException e) { + LOG.warn(e.getMessage(), e); + } finally { + if (conn != null) + try { + conn.close(); + } catch (JMSException e) { + LOG.warn(e.getMessage(), e); + } + } + } + } + + protected void setUp() throws Exception { + bindAddress = "vm://localhost"; + super.setUp(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setDeleteAllMessagesOnStartup(true); + answer.setUseJmx(false); + answer.setPersistent(isPersistent()); + answer.addConnector(bindAddress); + return answer; + } + + protected boolean isPersistent() { + return true; + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/CraigsBugTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/CraigsBugTest.java new file mode 100644 index 0000000000..f956da6d75 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/CraigsBugTest.java @@ -0,0 +1,67 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.command.ActiveMQQueue; + +public class CraigsBugTest extends EmbeddedBrokerTestSupport { + + private String connectionUri; + + public void testConnectionFactory() throws Exception { + final ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(connectionUri); + final ActiveMQQueue queue = new ActiveMQQueue("testqueue"); + final Connection conn = cf.createConnection(); + + Runnable r = new Runnable() { + public void run() { + try { + Session session = conn.createSession(false, 1); + MessageConsumer consumer = session.createConsumer(queue, null); + consumer.receive(1000); + } catch (JMSException e) { + e.printStackTrace(); + } + } + }; + new Thread(r).start(); + conn.start(); + + try { + synchronized (this) { + wait(3000); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:0"; + super.setUp(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/DoubleExpireTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/DoubleExpireTest.java new file mode 100644 index 0000000000..bb669434e2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/DoubleExpireTest.java @@ -0,0 +1,145 @@ +/** + * 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.bugs; + +import java.util.concurrent.TimeoutException; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.command.ActiveMQDestination; +import org.junit.Assert; + +public class DoubleExpireTest extends EmbeddedBrokerTestSupport { + + private static final long MESSAGE_TTL_MILLIS = 1000; + private static final long MAX_TEST_TIME_MILLIS = 60000; + + public void setUp() throws Exception { + setAutoFail(true); + setMaxTestTime(MAX_TEST_TIME_MILLIS); + super.setUp(); + } + + /** + * This test verifies that a message that expires can be be resent to queue + * with a new expiration and that it will be processed as a new message and + * allowed to re-expire. + *

+ * NOTE: This test fails on AMQ 5.4.2 because the originalExpiration + * timestamp is not cleared when the message is resent. + */ + public void testDoubleExpireWithoutMove() throws Exception { + // Create the default dead letter queue. + final ActiveMQDestination DLQ = createDestination("ActiveMQ.DLQ"); + + Connection conn = createConnection(); + try { + conn.start(); + Session session = conn.createSession(false, + Session.AUTO_ACKNOWLEDGE); + + // Verify that the test queue and DLQ are empty. + Assert.assertEquals(0, getSize(destination)); + Assert.assertEquals(0, getSize(DLQ)); + + // Enqueue a message to the test queue that will expire after 1s. + MessageProducer producer = session.createProducer(destination); + Message testMessage = session.createTextMessage("test message"); + producer.send(testMessage, Message.DEFAULT_DELIVERY_MODE, + Message.DEFAULT_PRIORITY, MESSAGE_TTL_MILLIS); + Assert.assertEquals(1, getSize(destination)); + + // Wait for the message to expire. + waitForSize(destination, 0, MAX_TEST_TIME_MILLIS); + Assert.assertEquals(1, getSize(DLQ)); + + // Consume the message from the DLQ and re-enqueue it to the test + // queue so that it expires after 1s. + MessageConsumer consumer = session.createConsumer(DLQ); + Message expiredMessage = consumer.receive(); + Assert.assertEquals(testMessage.getJMSMessageID(), expiredMessage + .getJMSMessageID()); + + producer.send(expiredMessage, Message.DEFAULT_DELIVERY_MODE, + Message.DEFAULT_PRIORITY, MESSAGE_TTL_MILLIS); + Assert.assertEquals(1, getSize(destination)); + Assert.assertEquals(0, getSize(DLQ)); + + // Verify that the resent message is "different" in that it has + // another ID. + Assert.assertNotSame(testMessage.getJMSMessageID(), expiredMessage + .getJMSMessageID()); + + // Wait for the message to re-expire. + waitForSize(destination, 0, MAX_TEST_TIME_MILLIS); + Assert.assertEquals(1, getSize(DLQ)); + + // Re-consume the message from the DLQ. + Message reexpiredMessage = consumer.receive(); + Assert.assertEquals(expiredMessage.getJMSMessageID(), reexpiredMessage + .getJMSMessageID()); + } finally { + conn.close(); + } + } + + /** + * A helper method that returns the embedded broker's implementation of a + * JMS queue. + */ + private Queue getPhysicalDestination(ActiveMQDestination destination) + throws Exception { + return (Queue) broker.getAdminView().getBroker().getDestinationMap() + .get(destination); + } + + /** + * A helper method that returns the size of the specified queue/topic. + */ + private long getSize(ActiveMQDestination destination) throws Exception { + return getPhysicalDestination(destination) != null ? getPhysicalDestination( + destination).getDestinationStatistics().getMessages() + .getCount() + : 0; + } + + /** + * A helper method that waits for a destination to reach a certain size. + */ + private void waitForSize(ActiveMQDestination destination, int size, + long timeoutMillis) throws Exception, TimeoutException { + long startTimeMillis = System.currentTimeMillis(); + + while (getSize(destination) != size + && System.currentTimeMillis() < (startTimeMillis + timeoutMillis)) { + Thread.sleep(250); + } + + if (getSize(destination) != size) { + throw new TimeoutException("Destination " + + destination.getPhysicalName() + " did not reach size " + + size + " within " + timeoutMillis + "ms."); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/DurableConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/DurableConsumerTest.java new file mode 100644 index 0000000000..eeee82b543 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/DurableConsumerTest.java @@ -0,0 +1,463 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; +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 javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import javax.management.ObjectName; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A Test case for AMQ-1479 + */ +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"; + protected BrokerService broker; + + protected String bindAddress = "tcp://localhost:61616"; + + protected byte[] payload = new byte[1024 * 32]; + protected ConnectionFactory factory; + protected 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 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); + try { + + topic = new ActiveMQTopic(topicName); + topicConnection = topicConnectionFactory.createTopicConnection(); + topicConnection.setClientID((clientId)); + topicConnection.start(); + + topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + topicSubscriber = topicSession.createDurableSubscriber(topic, (clientId)); + topicSubscriber.setMessageListener(this); + + } catch (JMSException e) { + e.printStackTrace(); + } + } + + public void onMessage(Message arg0){ + } + + public void closeConnection(){ + if (topicConnection != null) { + try { + topicConnection.close(); + } catch (JMSException e) { + } + } + } + + public void onException(JMSException exception){ + exceptions.add(exception); + } + } + + 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; + 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); + topicPublisher = topicSession.createPublisher(topic); + message = topicSession.createMessage(); + } catch (Exception ex) { + exceptions.add(ex); + } + while (shouldPublish) { + try { + topicPublisher.publish(message, DeliveryMode.PERSISTENT, 1, 2 * 60 * 60 * 1000); + } catch (JMSException ex) { + exceptions.add(ex); + } + try { + Thread.sleep(1); + } catch (Exception ex) { + } + } + } + } + + private void configurePersistence(BrokerService broker) throws Exception{ + File dataDirFile = new File("target/" + getName()); + KahaDBPersistenceAdapter kahaDBAdapter = new KahaDBPersistenceAdapter(); + kahaDBAdapter.setDirectory(dataDirFile); + broker.setPersistenceAdapter(kahaDBAdapter); + } + + public void testFailover() throws Exception{ + + configurePersistence(broker); + broker.start(); + + Thread publisherThread = new Thread(new MessagePublisher()); + publisherThread.start(); + final int numSubs = 100; + 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); + } + }); + thread.start(); + + } + + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + return numSubs == list.size(); + } + }); + + broker.stop(); + broker = createBroker(false); + configurePersistence(broker); + broker.start(); + Thread.sleep(10000); + for (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(){ + addCombinationValues("useDedicatedTaskRunner", new Object[] { Boolean.TRUE, Boolean.FALSE }); + } + + public void testConcurrentDurableConsumer() throws Exception{ + + broker.start(); + broker.waitUntilStarted(); + + factory = createConnectionFactory(); + final String topicName = getName(); + final int numMessages = 500; + 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++; + } + } + } while (msg == null); + + consumerConnection.close(); + } + assertTrue(received >= acked); + } catch (Exception e) { + e.printStackTrace(); + exceptions.add(e); + } + } + }; + + 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(); + ((ActiveMQConnection) producerConnection).setWatchTopicAdvisories(false); + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = producerSession.createTopic(topicName); + MessageProducer producer = producerSession.createProducer(topic); + producerConnection.start(); + for (int i = 0; i < numMessages; i++) { + 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; + } + }, 360 * 1000); + assertEquals("got required some messages", numMessages, receivedCount.get()); + assertTrue("no exceptions, but: " + exceptions, exceptions.isEmpty()); + } + + public void testConsumerRecover() throws Exception{ + doTestConsumer(true); + } + + public void testConsumer() throws Exception{ + doTestConsumer(false); + } + + public void testPrefetchViaBrokerConfig() throws Exception { + + Integer prefetchVal = new Integer(150); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setDurableTopicPrefetch(prefetchVal.intValue()); + policyEntry.setPrioritizedMessages(true); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(policyEntry); + broker.setDestinationPolicy(policyMap); + 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()); + MessageConsumer consumer = consumerSession.createDurableSubscriber(topic, CONSUMER_NAME); + consumerConnection.start(); + + ObjectName activeSubscriptionObjectName = broker.getAdminView().getDurableTopicSubscribers()[0]; + Object prefetchFromSubView = broker.getManagementContext().getAttribute(activeSubscriptionObjectName, "PrefetchSize"); + assertEquals(prefetchVal, prefetchFromSubView); + } + + public void doTestConsumer(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()); + MessageConsumer consumer = consumerSession.createDurableSubscriber(topic, CONSUMER_NAME); + consumerConnection.start(); + consumerConnection.close(); + broker.stop(); + broker = createBroker(false); + if (forceRecover) { + configurePersistence(broker); + } + broker.start(); + + Connection producerConnection = factory.createConnection(); + + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = producerSession.createProducer(topic); + producerConnection.start(); + for (int i = 0; i < COUNT; i++) { + BytesMessage msg = producerSession.createBytesMessage(); + msg.writeBytes(payload); + producer.send(msg); + if (i != 0 && i % 1000 == 0) { + LOG.info("Sent msg " + i); + } + } + producerConnection.close(); + broker.stop(); + broker = createBroker(false); + if (forceRecover) { + configurePersistence(broker); + } + broker.start(); + + 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); + assertNotNull("Missing message: " + i, msg); + if (i != 0 && i % 1000 == 0) { + LOG.info("Received msg " + i); + } + + } + consumerConnection.close(); + + } + + @Override + protected void setUp() throws Exception{ + if (broker == null) { + broker = createBroker(true); + } + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception{ + super.tearDown(); + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + } + + protected Topic creatTopic(Session s,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(); + configureBroker(answer, deleteStore); + return answer; + } + + protected void configureBroker(BrokerService answer,boolean deleteStore) throws Exception{ + answer.setDeleteAllMessagesOnStartup(deleteStore); + KahaDBStore kaha = new KahaDBStore(); + //kaha.setConcurrentStoreAndDispatchTopics(false); + 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); + factory.setUseDedicatedTaskRunner(useDedicatedTaskRunner); + return factory; + } + + public static Test suite(){ + return suite(DurableConsumerTest.class); + } + + public static void main(String[] args){ + junit.textui.TestRunner.run(suite()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JMSDurableTopicNoLocalTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JMSDurableTopicNoLocalTest.java new file mode 100644 index 0000000000..80c4e9fc50 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JMSDurableTopicNoLocalTest.java @@ -0,0 +1,83 @@ +/** + * 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.bugs; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; + +/** + * + */ +public class JMSDurableTopicNoLocalTest extends EmbeddedBrokerTestSupport { + protected String bindAddress; + + public void testConsumeNoLocal() throws Exception { + final String TEST_NAME = getClass().getName(); + Connection connection = createConnection(); + connection.setClientID(TEST_NAME); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + TopicSubscriber subscriber = session.createDurableSubscriber((Topic) destination, "topicUser2", null, true); + + + final CountDownLatch latch = new CountDownLatch(1); + subscriber.setMessageListener(new MessageListener() { + public void onMessage(Message message) { + System.out.println("Receive a message " + message); + latch.countDown(); + } + }); + + connection.start(); + + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("THIS IS A TEST"); + producer.send(message); + producer.close(); + latch.await(5,TimeUnit.SECONDS); + assertEquals(latch.getCount(),1); + } + + @Override + protected void setUp() throws Exception { + bindAddress = "vm://localhost"; + useTopic=true; + super.setUp(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseJmx(false); + answer.setPersistent(true); + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(bindAddress); + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JmsDurableTopicSlowReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JmsDurableTopicSlowReceiveTest.java new file mode 100644 index 0000000000..05a8c1d2c3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JmsDurableTopicSlowReceiveTest.java @@ -0,0 +1,180 @@ +/** + * 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.bugs; + +import java.util.Properties; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.test.JmsTopicSendReceiveTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsDurableTopicSlowReceiveTest extends JmsTopicSendReceiveTest { + + static final int NMSG = 200; + static final int MSIZE = 256000; + private static final transient Logger LOG = LoggerFactory.getLogger(JmsDurableTopicSlowReceiveTest.class); + private static final String COUNT_PROPERY_NAME = "count"; + + protected Connection connection2; + protected Session session2; + protected Session consumeSession2; + protected MessageConsumer consumer2; + protected MessageProducer producer2; + protected Destination consumerDestination2; + BrokerService broker; + private Connection connection3; + private Session consumeSession3; + private TopicSubscriber consumer3; + + /** + * Set up a durable suscriber test. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + this.durable = true; + broker = createBroker(); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + broker.stop(); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory result = new ActiveMQConnectionFactory("vm://localhost?async=false"); + Properties props = new Properties(); + props.put("prefetchPolicy.durableTopicPrefetch", "5"); + props.put("prefetchPolicy.optimizeDurableTopicPrefetch", "5"); + result.setProperties(props); + return result; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.setDeleteAllMessagesOnStartup(true); + } + + /** + * Test if all the messages sent are being received. + * + * @throws Exception + */ + public void testSlowReceiver() throws Exception { + connection2 = createConnection(); + connection2.setClientID("test"); + connection2.start(); + consumeSession2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerDestination2 = session2.createTopic(getConsumerSubject() + "2"); + consumer2 = consumeSession2.createDurableSubscriber((Topic)consumerDestination2, getName()); + + consumer2.close(); + connection2.close(); + new Thread(new Runnable() { + + public void run() { + try { + int count = 0; + for (int loop = 0; loop < 4; loop++) { + connection2 = createConnection(); + connection2.start(); + session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer2 = session2.createProducer(null); + producer2.setDeliveryMode(deliveryMode); + Thread.sleep(1000); + for (int i = 0; i < NMSG / 4; i++) { + BytesMessage message = session2.createBytesMessage(); + message.writeBytes(new byte[MSIZE]); + message.setStringProperty("test", "test"); + message.setIntProperty(COUNT_PROPERY_NAME, count); + message.setJMSType("test"); + producer2.send(consumerDestination2, message); + Thread.sleep(50); + if (verbose) { + LOG.debug("Sent(" + loop + "): " + i); + } + count++; + } + producer2.close(); + connection2.stop(); + connection2.close(); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + }, "SENDER Thread").start(); + connection3 = createConnection(); + connection3.setClientID("test"); + connection3.start(); + consumeSession3 = connection3.createSession(false, Session.CLIENT_ACKNOWLEDGE); + consumer3 = consumeSession3.createDurableSubscriber((Topic)consumerDestination2, getName()); + connection3.close(); + int count = 0; + for (int loop = 0; loop < 4; ++loop) { + connection3 = createConnection(); + connection3.setClientID("test"); + connection3.start(); + consumeSession3 = connection3.createSession(false, Session.CLIENT_ACKNOWLEDGE); + consumer3 = consumeSession3.createDurableSubscriber((Topic)consumerDestination2, getName()); + Message msg = null; + int i; + for (i = 0; i < NMSG / 4; i++) { + msg = consumer3.receive(10000); + if (msg == null) { + break; + } + if (verbose) { + LOG.debug("Received(" + loop + "): " + i + " count = " + msg.getIntProperty(COUNT_PROPERY_NAME)); + } + assertNotNull(msg); + assertEquals(msg.getJMSType(), "test"); + assertEquals(msg.getStringProperty("test"), "test"); + assertEquals("Messages received out of order", count, msg.getIntProperty(COUNT_PROPERY_NAME)); + Thread.sleep(500); + msg.acknowledge(); + count++; + } + consumer3.close(); + assertEquals("Receiver " + loop, NMSG / 4, i); + connection3.close(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JmsTimeoutTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JmsTimeoutTest.java new file mode 100644 index 0000000000..2858302425 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/JmsTimeoutTest.java @@ -0,0 +1,158 @@ +/** + * 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.bugs; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.ResourceAllocationException; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.transport.RequestTimedOutIOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JmsTimeoutTest extends EmbeddedBrokerTestSupport { + + static final Logger LOG = LoggerFactory.getLogger(JmsTimeoutTest.class); + + private final int messageSize=1024*64; + private final int messageCount=10000; + private final AtomicInteger exceptionCount = new AtomicInteger(0); + + /** + * Test the case where the broker is blocked due to a memory limit + * and a producer timeout is set on the connection. + * @throws Exception + */ + public void testBlockedProducerConnectionTimeout() throws Exception { + final ActiveMQConnection cx = (ActiveMQConnection)createConnection(); + final ActiveMQDestination queue = createDestination("testqueue"); + + // we should not take longer than 10 seconds to return from send + cx.setSendTimeout(10000); + + Runnable r = new Runnable() { + public void run() { + try { + LOG.info("Sender thread starting"); + Session session = cx.createSession(false, 1); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + TextMessage message = session.createTextMessage(createMessageText()); + for(int count=0; count 0); + } + + /** + * Test the case where the broker is blocked due to a memory limit + * with a fail timeout + * @throws Exception + */ + public void testBlockedProducerUsageSendFailTimeout() throws Exception { + final ActiveMQConnection cx = (ActiveMQConnection)createConnection(); + final ActiveMQDestination queue = createDestination("testqueue"); + + broker.getSystemUsage().setSendFailIfNoSpaceAfterTimeout(5000); + Runnable r = new Runnable() { + public void run() { + try { + LOG.info("Sender thread starting"); + Session session = cx.createSession(false, 1); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + TextMessage message = session.createTextMessage(createMessageText()); + for(int count=0; count 0); + } + + protected void setUp() throws Exception { + exceptionCount.set(0); + bindAddress = "tcp://localhost:0"; + broker = createBroker(); + broker.setDeleteAllMessagesOnStartup(true); + broker.getSystemUsage().getMemoryUsage().setLimit(5*1024*1024); + + super.setUp(); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getPublishableConnectString()); + } + + private String createMessageText() { + StringBuffer buffer = new StringBuffer(); + buffer.append(""); + for (int i = buffer.length(); i < messageSize; i++) { + buffer.append('X'); + } + buffer.append(""); + return buffer.toString(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageBlockResumeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageBlockResumeTest.java new file mode 100644 index 0000000000..e8d5371139 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageBlockResumeTest.java @@ -0,0 +1,224 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runner.RunWith; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.*; + + +@RunWith(BlockJUnit4ClassRunner.class) +public class MemoryUsageBlockResumeTest extends TestSupport implements Thread.UncaughtExceptionHandler { + + public int deliveryMode = DeliveryMode.PERSISTENT; + + private static final Logger LOG = LoggerFactory.getLogger(MemoryUsageBlockResumeTest.class); + private static byte[] buf = new byte[4 * 1024]; + private static byte[] bigBuf = new byte[48 * 1024]; + + private BrokerService broker; + AtomicInteger messagesSent = new AtomicInteger(0); + AtomicInteger messagesConsumed = new AtomicInteger(0); + + protected long messageReceiveTimeout = 10000L; + + Destination destination = new ActiveMQQueue("FooTwo"); + Destination bigDestination = new ActiveMQQueue("FooTwoBig"); + + private String connectionUri; + private final Vector exceptions = new Vector(); + + @Test(timeout = 60 * 1000) + public void testBlockByOtherResumeNoException() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + + // ensure more than on message can be pending when full + factory.setProducerWindowSize(48*1024); + // ensure messages are spooled to disk for this consumer + ActiveMQPrefetchPolicy prefetch = new ActiveMQPrefetchPolicy(); + prefetch.setTopicPrefetch(10); + factory.setPrefetchPolicy(prefetch); + Connection consumerConnection = factory.createConnection(); + consumerConnection.start(); + + Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(bigDestination); + + final Connection producerConnection = factory.createConnection(); + producerConnection.start(); + + final int fillWithBigCount = 10; + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + producer.setDeliveryMode(deliveryMode); + for (int idx = 0; idx < fillWithBigCount; ++idx) { + Message message = session.createTextMessage(new String(bigBuf) + idx); + producer.send(bigDestination, message); + messagesSent.incrementAndGet(); + LOG.info("After big: " + idx + ", System Memory Usage " + broker.getSystemUsage().getMemoryUsage().getPercentUsage()); + } + + // will block on pfc + final int toSend = 20; + Thread producingThread = new Thread("Producing thread") { + @Override + public void run() { + try { + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + for (int idx = 0; idx < toSend; ++idx) { + Message message = session.createTextMessage(new String(buf) + idx); + producer.send(destination, message); + messagesSent.incrementAndGet(); + LOG.info("After little:" + idx + ", System Memory Usage " + broker.getSystemUsage().getMemoryUsage().getPercentUsage()); + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + producingThread.start(); + + Thread producingThreadTwo = new Thread("Producing thread") { + @Override + public void run() { + try { + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + for (int idx = 0; idx < toSend; ++idx) { + Message message = session.createTextMessage(new String(buf) + idx); + producer.send(destination, message); + messagesSent.incrementAndGet(); + LOG.info("After little:" + idx + ", System Memory Usage " + broker.getSystemUsage().getMemoryUsage().getPercentUsage()); + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + producingThreadTwo.start(); + + assertTrue("producer has sent x in a reasonable time", Wait.waitFor(new Wait.Condition() + { + @Override + public boolean isSatisified() throws Exception { + LOG.info("Checking for : X sent, System Memory Usage " + broker.getSystemUsage().getMemoryUsage().getPercentUsage() + ", sent: " + messagesSent); + return messagesSent.get() > 20; + } + })); + + + LOG.info("Consuming from big q to allow delivery to smaller q from pending"); + int count = 0; + + Message m = null; + + for (;count < 10; count++) { + assertTrue((m = consumer.receive(messageReceiveTimeout)) != null); + LOG.info("Recieved Message (" + count + "):" + m + ", System Memory Usage " + broker.getSystemUsage().getMemoryUsage().getPercentUsage()); + messagesConsumed.incrementAndGet(); + } + consumer.close(); + + producingThread.join(); + producingThreadTwo.join(); + + assertEquals("Incorrect number of Messages Sent: " + messagesSent.get(), messagesSent.get(), fillWithBigCount + toSend*2); + + // consume all little messages + consumer = consumerSession.createConsumer(destination); + for (count = 0;count < toSend*2; count++) { + assertTrue((m = consumer.receive(messageReceiveTimeout)) != null); + LOG.info("Recieved Message (" + count + "):" + m + ", System Memory Usage " + broker.getSystemUsage().getMemoryUsage().getPercentUsage() ); + messagesConsumed.incrementAndGet(); + } + + assertEquals("Incorrect number of Messages consumed: " + messagesConsumed.get(), messagesSent.get(), messagesConsumed.get()); + + //assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + } + + @Override + @Before + public void setUp() throws Exception { + + Thread.setDefaultUncaughtExceptionHandler(this); + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(false); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + + setDefaultPersistenceAdapter(broker); + broker.getSystemUsage().getMemoryUsage().setLimit((30 * 16 * 1024)); + + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setOptimizedDispatch(true); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultPolicy); + broker.setDestinationPolicy(policyMap); + + broker.addConnector("tcp://localhost:0"); + broker.start(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + @Override + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error("Unexpected Unhandeled ex on: " + t, e); + exceptions.add(e); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageBrokerTest.java new file mode 100644 index 0000000000..b229e0e8f0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageBrokerTest.java @@ -0,0 +1,90 @@ +/** + * 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.bugs; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTestSupport; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.IOHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; +import java.io.File; + +public class MemoryUsageBrokerTest extends BrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(MemoryUsageBrokerTest.class); + + protected void setUp() throws Exception { + this.setAutoFail(true); + super.setUp(); + } + + @Override + protected PolicyEntry getDefaultPolicy() { + PolicyEntry policy = super.getDefaultPolicy(); + // Disable PFC and assign a large memory limit that's larger than the default broker memory limit for queues + policy.setProducerFlowControl(false); + policy.setQueue(">"); + policy.setMemoryLimit(128 * 1024 * 1024); + return policy; + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + KahaDBStore kaha = new KahaDBStore(); + File directory = new File("target/activemq-data/kahadb"); + IOHelper.deleteChildren(directory); + kaha.setDirectory(directory); + kaha.deleteAllMessages(); + broker.setPersistenceAdapter(kaha); + return broker; + } + + protected ConnectionFactory createConnectionFactory() { + return new ActiveMQConnectionFactory(broker.getVmConnectorURI()); + } + + protected Connection createJmsConnection() throws JMSException { + return createConnectionFactory().createConnection(); + } + + public void testMemoryUsage() throws Exception { + Connection conn = createJmsConnection(); + Session session = conn.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue("queue.a.b"); + MessageProducer producer = session.createProducer(queue); + for (int i = 0; i < 100000; i++) { + BytesMessage bm = session.createBytesMessage(); + bm.writeBytes(new byte[1024]); + producer.send(bm); + if ((i + 1) % 100 == 0) { + session.commit(); + int memoryUsagePercent = broker.getSystemUsage().getMemoryUsage().getPercentUsage(); + LOG.info((i + 1) + " messages have been sent; broker memory usage " + memoryUsagePercent + "%"); + assertTrue("Used more than available broker memory", memoryUsagePercent <= 100); + } + } + session.commit(); + producer.close(); + session.close(); + conn.close(); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageCleanupTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageCleanupTest.java new file mode 100644 index 0000000000..e7feb90054 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MemoryUsageCleanupTest.java @@ -0,0 +1,255 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MemoryUsageCleanupTest { + + private static final Logger LOG = LoggerFactory.getLogger(MemoryUsageCleanupTest.class); + private static final String QUEUE_NAME = MemoryUsageCleanupTest.class.getName() + "Queue"; + + private final String str = new String( + "QAa0bcLdUK2eHfJgTP8XhiFj61DOklNm9nBoI5pGqYVrs3CtSuMZvwWx4yE7zR"); + + private BrokerService broker; + private String connectionUri; + private ExecutorService pool; + private String queueName; + private Random r = new Random(); + + @Before + public void setUp() throws Exception { + + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setDedicatedTaskRunner(false); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + + SharedDeadLetterStrategy strategy = new SharedDeadLetterStrategy(); + strategy.setProcessExpired(false); + strategy.setProcessNonPersistent(false); + + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setQueue(">"); + defaultPolicy.setOptimizedDispatch(true); + defaultPolicy.setDeadLetterStrategy(strategy); + defaultPolicy.setMemoryLimit(300000000); + + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultPolicy); + + broker.setDestinationPolicy(policyMap); + + broker.getSystemUsage().getMemoryUsage().setLimit(300000000L); + + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + pool = Executors.newFixedThreadPool(10); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + + if (pool != null) { + pool.shutdown(); + } + } + + @Test + public void testIt() throws Exception { + + final int startPercentage = broker.getAdminView().getMemoryPercentUsage(); + LOG.info("MemoryUseage at test start = " + startPercentage); + + for (int i = 0; i < 2; i++) { + LOG.info("Started the test iteration: " + i + " using queueName = " + queueName); + queueName = QUEUE_NAME + i; + final CountDownLatch latch = new CountDownLatch(11); + + pool.execute(new Runnable() { + @Override + public void run() { + receiveAndDiscard100messages(latch); + } + }); + + for (int j = 0; j < 10; j++) { + pool.execute(new Runnable() { + @Override + public void run() { + send10000messages(latch); + } + }); + } + + LOG.info("Waiting on the send / receive latch"); + latch.await(5, TimeUnit.MINUTES); + LOG.info("Resumed"); + + destroyQueue(); + TimeUnit.SECONDS.sleep(2); + } + + LOG.info("MemoryUseage before awaiting temp store cleanup = " + broker.getAdminView().getMemoryPercentUsage()); + + assertTrue("MemoryUsage should return to: " + startPercentage + + "% but was " + broker.getAdminView().getMemoryPercentUsage() + "%", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return broker.getAdminView().getMemoryPercentUsage() <= startPercentage + 1; + } + })); + + int endPercentage = broker.getAdminView().getMemoryPercentUsage(); + LOG.info("MemoryUseage at test end = " + endPercentage); + } + + public void destroyQueue() { + try { + Broker broker = this.broker.getBroker(); + if (!broker.isStopped()) { + LOG.info("Removing: " + queueName); + broker.removeDestination(this.broker.getAdminConnectionContext(), new ActiveMQQueue(queueName), 10); + } + } catch (Exception e) { + LOG.warn("Got an error while removing the test queue", e); + } + } + + private void send10000messages(CountDownLatch latch) { + ActiveMQConnection activeMQConnection = null; + try { + activeMQConnection = createConnection(null); + Session session = activeMQConnection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session + .createQueue(queueName)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + activeMQConnection.start(); + for (int i = 0; i < 10000; i++) { + TextMessage textMessage = session.createTextMessage(); + textMessage.setText(generateBody(1000)); + textMessage.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(textMessage); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + producer.close(); + } catch (JMSException e) { + LOG.warn("Got an error while sending the messages", e); + } finally { + if (activeMQConnection != null) { + try { + activeMQConnection.close(); + } catch (JMSException e) { + } + } + } + latch.countDown(); + } + + private void receiveAndDiscard100messages(CountDownLatch latch) { + ActiveMQConnection activeMQConnection = null; + try { + activeMQConnection = createConnection(null); + Session session = activeMQConnection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + MessageConsumer messageConsumer = session.createConsumer( + session.createQueue(queueName)); + activeMQConnection.start(); + for (int i = 0; i < 100; i++) { + messageConsumer.receive(); + } + messageConsumer.close(); + LOG.info("Created and disconnected"); + } catch (JMSException e) { + LOG.warn("Got an error while receiving the messages", e); + } finally { + if (activeMQConnection != null) { + try { + activeMQConnection.close(); + } catch (JMSException e) { + } + } + } + latch.countDown(); + } + + private ActiveMQConnection createConnection(String id) throws JMSException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + if (id != null) { + factory.setClientID(id); + } + + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + return connection; + } + + private String generateBody(int length) { + + StringBuilder sb = new StringBuilder(); + int te = 0; + for (int i = 1; i <= length; i++) { + te = r.nextInt(62); + sb.append(str.charAt(te)); + } + return sb.toString(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MessageExpirationReaperTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MessageExpirationReaperTest.java new file mode 100644 index 0000000000..4c8527a52c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MessageExpirationReaperTest.java @@ -0,0 +1,185 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import javax.jms.*; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test to determine if expired messages are being reaped if there is + * no active consumer connected to the broker. + */ +public class MessageExpirationReaperTest { + + private BrokerService broker; + private ConnectionFactory factory; + private ActiveMQConnection connection; + private final String destinationName = "TEST.Q"; + private final String brokerUrl = "tcp://localhost:0"; + private final String brokerName = "testBroker"; + private String connectionUri; + + @Before + public void init() throws Exception { + createBroker(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + + factory = createConnectionFactory(); + connection = (ActiveMQConnection) factory.createConnection(); + connection.setClientID("test-connection"); + connection.start(); + } + + @After + public void cleanUp() throws Exception { + connection.close(); + broker.stop(); + } + + protected void createBroker() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setBrokerName(brokerName); + broker.addConnector(brokerUrl); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setExpireMessagesPeriod(500); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + + broker.start(); + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(connectionUri); + } + + protected Session createSession() throws Exception { + return connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + @Test + public void testExpiredMessageReaping() throws Exception { + + Session producerSession = createSession(); + ActiveMQDestination destination = (ActiveMQDestination) producerSession.createQueue(destinationName); + MessageProducer producer = producerSession.createProducer(destination); + producer.setTimeToLive(1000); + + final int count = 3; + // Send some messages with an expiration + for (int i = 0; i < count; i++) { + TextMessage message = producerSession.createTextMessage("" + i); + producer.send(message); + } + + // Let the messages expire + Thread.sleep(2000); + + DestinationViewMBean view = createView(destination); + + assertEquals("Incorrect inflight count: " + view.getInFlightCount(), 0, view.getInFlightCount()); + assertEquals("Incorrect queue size count", 0, view.getQueueSize()); + assertEquals("Incorrect expired size count", view.getEnqueueCount(), view.getExpiredCount()); + + // Send more messages with an expiration + for (int i = 0; i < count; i++) { + TextMessage message = producerSession.createTextMessage("" + i); + producer.send(message); + } + + // Let the messages expire + Thread.sleep(2000); + + // Simply browse the queue + Session browserSession = createSession(); + QueueBrowser browser = browserSession.createBrowser((Queue) destination); + assertFalse("no message in the browser", browser.getEnumeration().hasMoreElements()); + + // The messages expire and should be reaped because of the presence of + // the queue browser + assertEquals("Wrong inFlightCount: " + view.getInFlightCount(), 0, view.getInFlightCount()); + } + + @Test + public void testExpiredMessagesOnTopic() throws Exception{ + Session session = createSession(); + + // use a zero prefetch so messages don't go inflight + ActiveMQTopic destination = new ActiveMQTopic(destinationName + "?consumer.prefetchSize=0"); + + MessageProducer producer = session.createProducer(destination); + + // should have a durable sub because it's a little tricky to get messages to expire in + // non-durable subs.. with durable subs, we can just expire in the topic using the expire + // period.. also.. durable sub has to be "inactive" for the expire checker to actually + // expire the messages + MessageConsumer consumer = session.createDurableSubscriber(destination, "test-durable"); + + producer.setTimeToLive(500); + + final int count = 3; + // Send some messages with an expiration + for (int i = 0; i < count; i++) { + TextMessage message = session.createTextMessage("" + i); + producer.send(message); + } + + DestinationViewMBean view = createView(destination); + // not expired yet... + assertEquals("Incorrect enqueue count", 3, view.getEnqueueCount() ); + + // close consumer so topic thinks consumer is inactive + consumer.close(); + + // Let the messages reach an expiry time + Thread.sleep(2000); + + assertEquals("Incorrect inflight count: " + view.getInFlightCount(), 0, view.getInFlightCount()); + assertEquals("Incorrect queue size count", 0, view.getQueueSize()); + assertEquals("Incorrect expired size count", view.getEnqueueCount(), view.getExpiredCount()); + } + + protected DestinationViewMBean createView(ActiveMQDestination destination) throws Exception { + String domain = "org.apache.activemq"; + ObjectName name; + if (destination.isQueue()) { + name = new ObjectName(domain + ":type=Broker,brokerName=" + brokerName + ",destinationType=Queue,destinationName=" + destinationName); + } else { + name = new ObjectName(domain + ":type=Broker,brokerName=" + brokerName + ",destinationType=Topic,destinationName=" + destinationName); + } + return (DestinationViewMBean) broker.getManagementContext().newProxyInstance(name, DestinationViewMBean.class, + true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MessageSender.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MessageSender.java new file mode 100644 index 0000000000..f85bdba8d9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MessageSender.java @@ -0,0 +1,45 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Session; + +public class MessageSender { + private MessageProducer producer; + private Session session; + + public MessageSender(String queueName, Connection connection, boolean useTransactedSession, boolean topic) throws Exception { + session = useTransactedSession ? connection.createSession(true, Session.SESSION_TRANSACTED) : connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(topic ? session.createTopic(queueName) : session.createQueue(queueName)); + } + + public void send(String payload) throws Exception { + ObjectMessage message = session.createObjectMessage(); + message.setObject(payload); + producer.send(message); + if (session.getTransacted()) { + session.commit(); + } + } + + public MessageProducer getProducer() { + return producer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MissingDataFileTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MissingDataFileTest.java new file mode 100644 index 0000000000..68055bbbe9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/MissingDataFileTest.java @@ -0,0 +1,323 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.ObjectMessage; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.usage.SystemUsage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * Try and replicate: + * Caused by: java.io.IOException: Could not locate data file data--188 + * at org.apache.activemq.kaha.impl.async.AsyncDataManager.getDataFile(AsyncDataManager.java:302) + * at org.apache.activemq.kaha.impl.async.AsyncDataManager.read(AsyncDataManager.java:614) + * at org.apache.activemq.store.amq.AMQPersistenceAdapter.readCommand(AMQPersistenceAdapter.java:523) + */ + +public class MissingDataFileTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(MissingDataFileTest.class); + + private static int counter = 500; + + private static int hectorToHaloCtr; + private static int xenaToHaloCtr; + private static int troyToHaloCtr; + + private static int haloToHectorCtr; + private static int haloToXenaCtr; + private static int haloToTroyCtr; + + private final String hectorToHalo = "hectorToHalo"; + private final String xenaToHalo = "xenaToHalo"; + private final String troyToHalo = "troyToHalo"; + + private final String haloToHector = "haloToHector"; + private final String haloToXena = "haloToXena"; + private final String haloToTroy = "haloToTroy"; + + + private BrokerService broker; + + private Connection hectorConnection; + private Connection xenaConnection; + private Connection troyConnection; + private Connection haloConnection; + + private final Object lock = new Object(); + final boolean useTopic = false; + final boolean useSleep = true; + + protected static final String payload = new String(new byte[500]); + + public Connection createConnection() throws JMSException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + return factory.createConnection(); + } + + public Session createSession(Connection connection, boolean transacted) throws JMSException { + return connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE); + } + + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.addConnector("tcp://localhost:61616").setName("Default"); + + SystemUsage systemUsage; + systemUsage = new SystemUsage(); + systemUsage.getMemoryUsage().setLimit(10 * 1024 * 1024); // Just a few messags + broker.setSystemUsage(systemUsage); + + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = new KahaDBPersistenceAdapter(); + kahaDBPersistenceAdapter.setJournalMaxFileLength(16*1024); + kahaDBPersistenceAdapter.setCleanupInterval(500); + broker.setPersistenceAdapter(kahaDBPersistenceAdapter); + + broker.start(); + LOG.info("Starting broker.."); + } + + @Override + public void tearDown() throws Exception { + hectorConnection.close(); + xenaConnection.close(); + troyConnection.close(); + haloConnection.close(); + broker.stop(); + } + + public void testForNoDataFoundError() throws Exception { + + startBroker(); + hectorConnection = createConnection(); + Thread hectorThread = buildProducer(hectorConnection, hectorToHalo, false, useTopic); + Receiver hHectorReceiver = new Receiver() { + @Override + public void receive(String s) throws Exception { + haloToHectorCtr++; + if (haloToHectorCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + possiblySleep(haloToHectorCtr); + } + }; + buildReceiver(hectorConnection, haloToHector, false, hHectorReceiver, useTopic); + + troyConnection = createConnection(); + Thread troyThread = buildProducer(troyConnection, troyToHalo); + Receiver hTroyReceiver = new Receiver() { + @Override + public void receive(String s) throws Exception { + haloToTroyCtr++; + if (haloToTroyCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + possiblySleep(haloToTroyCtr); + } + }; + buildReceiver(hectorConnection, haloToTroy, false, hTroyReceiver, false); + + xenaConnection = createConnection(); + Thread xenaThread = buildProducer(xenaConnection, xenaToHalo); + Receiver hXenaReceiver = new Receiver() { + @Override + public void receive(String s) throws Exception { + haloToXenaCtr++; + if (haloToXenaCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + possiblySleep(haloToXenaCtr); + } + }; + buildReceiver(xenaConnection, haloToXena, false, hXenaReceiver, false); + + haloConnection = createConnection(); + 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() { + @Override + public void receive(String s) throws Exception { + hectorToHaloCtr++; + troySender.send(payload); + if (hectorToHaloCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + possiblySleep(hectorToHaloCtr); + } + } + }; + Receiver xenaReceiver = new Receiver() { + @Override + public void receive(String s) throws Exception { + xenaToHaloCtr++; + hectorSender.send(payload); + if (xenaToHaloCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + possiblySleep(xenaToHaloCtr); + } + }; + Receiver troyReceiver = new Receiver() { + @Override + public void receive(String s) throws Exception { + troyToHaloCtr++; + xenaSender.send(payload); + if (troyToHaloCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + }; + buildReceiver(haloConnection, hectorToHalo, true, hectorReceiver, false); + buildReceiver(haloConnection, xenaToHalo, true, xenaReceiver, false); + buildReceiver(haloConnection, troyToHalo, true, troyReceiver, false); + + haloConnection.start(); + + troyConnection.start(); + troyThread.start(); + + xenaConnection.start(); + xenaThread.start(); + + hectorConnection.start(); + hectorThread.start(); + waitForMessagesToBeDelivered(); + // number of messages received should match messages sent + assertEquals(hectorToHaloCtr, counter); + LOG.info("hectorToHalo received " + hectorToHaloCtr + " messages"); + assertEquals(xenaToHaloCtr, counter); + LOG.info("xenaToHalo received " + xenaToHaloCtr + " messages"); + assertEquals(troyToHaloCtr, counter); + LOG.info("troyToHalo received " + troyToHaloCtr + " messages"); + assertEquals(haloToHectorCtr, counter); + LOG.info("haloToHector received " + haloToHectorCtr + " messages"); + assertEquals(haloToXenaCtr, counter); + LOG.info("haloToXena received " + haloToXenaCtr + " messages"); + assertEquals(haloToTroyCtr, counter); + LOG.info("haloToTroy received " + haloToTroyCtr + " messages"); + + } + + protected void possiblySleep(int count) throws InterruptedException { + if (useSleep) { + if (count % 100 == 0) { + Thread.sleep(5000); + } + } + + } + + protected void waitForMessagesToBeDelivered() { + // let's give the listeners enough time to read all messages + long maxWaitTime = counter * 1000; + long waitTime = maxWaitTime; + long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); + + synchronized (lock) { + boolean hasMessages = true; + while (hasMessages && waitTime >= 0) { + try { + lock.wait(200); + } catch (InterruptedException e) { + LOG.error(e.toString()); + } + // check if all messages have been received + hasMessages = hectorToHaloCtr < counter || xenaToHaloCtr < counter || troyToHaloCtr < counter || haloToHectorCtr < counter || haloToXenaCtr < counter + || haloToTroyCtr < counter; + waitTime = maxWaitTime - (System.currentTimeMillis() - start); + } + } + } + + public MessageSender buildTransactionalProducer(String queueName, Connection connection, boolean isTopic) throws Exception { + + return new MessageSender(queueName, connection, true, isTopic); + } + + public Thread buildProducer(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 { + final MessageSender producer = new MessageSender(queueName, connection, transacted, isTopic); + Thread thread = new Thread() { + @Override + public synchronized void run() { + for (int i = 0; i < counter; i++) { + try { + producer.send(payload ); + } catch (Exception e) { + throw new RuntimeException("on " + queueName + " send", e); + } + } + } + }; + return thread; + } + + public void buildReceiver(Connection connection, final String queueName, boolean transacted, final Receiver receiver, 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(); + } + } + }; + inputMessageConsumer.setMessageListener(messageListener); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/OptimizeAcknowledgeWithExpiredMsgsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/OptimizeAcknowledgeWithExpiredMsgsTest.java new file mode 100644 index 0000000000..195ccbd030 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/OptimizeAcknowledgeWithExpiredMsgsTest.java @@ -0,0 +1,312 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test for AMQ-3965. + * A consumer may be stalled in case it uses optimizeAcknowledge and receives + * a number of messages that expire before being dispatched to application code. + * See for more details. + * + */ +public class OptimizeAcknowledgeWithExpiredMsgsTest { + + private final static Logger LOG = LoggerFactory.getLogger(OptimizeAcknowledgeWithExpiredMsgsTest.class); + + private BrokerService broker = null; + + private String connectionUri; + + /** + * Creates a broker instance but does not start it. + * + * @param brokerUri - transport uri of broker + * @param brokerName - name for the broker + * @return a BrokerService instance with transport uri and broker name set + * @throws Exception + */ + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.setUseJmx(false); + connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString(); + return broker; + } + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + } + + /** + * Tests for AMQ-3965 + * Creates connection into broker using optimzeAcknowledge and prefetch=100 + * Creates producer and consumer. Producer sends 45 msgs that will expire + * at consumer (but before being dispatched to app code). + * Producer then sends 60 msgs without expiry. + * + * Consumer receives msgs using a MessageListener and increments a counter. + * Main thread sleeps for 5 seconds and checks the counter value. + * If counter != 60 msgs (the number of msgs that should get dispatched + * to consumer) the test fails. + */ + @Test + public void testOptimizedAckWithExpiredMsgs() throws Exception + { + ActiveMQConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(connectionUri + "?jms.optimizeAcknowledge=true&jms.prefetchPolicy.all=100"); + + // Create JMS resources + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue("TEST.FOO"); + + // ***** Consumer code ***** + MessageConsumer consumer = session.createConsumer(destination); + + final MyMessageListener listener = new MyMessageListener(); + connection.setExceptionListener((ExceptionListener) listener); + + // ***** Producer Code ***** + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode(); + TextMessage message; + + // Produce msgs that will expire quickly + for (int i=0; i<45; i++) { + message = session.createTextMessage(text); + producer.send(message,1,1,100); + LOG.trace("Sent message: "+ message.getJMSMessageID() + + " with expiry 10 msec"); + } + // Produce msgs that don't expire + for (int i=0; i<60; i++) { + message = session.createTextMessage(text); + producer.send(message,1,1,60000); + // producer.send(message); + LOG.trace("Sent message: "+ message.getJMSMessageID() + + " with expiry 30 sec"); + } + consumer.setMessageListener(listener); + + sleep(1000); // let the batch of 45 expire. + + connection.start(); + + assertTrue("Should receive all expected messages, counter at " + listener.getCounter(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return listener.getCounter() == 60; + } + })); + + LOG.info("Received all expected messages with counter at: " + listener.getCounter()); + + // Cleanup + producer.close(); + consumer.close(); + session.close(); + connection.close(); + } + + @Test + public void testOptimizedAckWithExpiredMsgsSync() throws Exception + { + ActiveMQConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(connectionUri + "?jms.optimizeAcknowledge=true&jms.prefetchPolicy.all=100"); + + // Create JMS resources + Connection connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue("TEST.FOO"); + + // ***** Consumer code ***** + MessageConsumer consumer = session.createConsumer(destination); + + // ***** Producer Code ***** + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode(); + TextMessage message; + + // Produce msgs that will expire quickly + for (int i=0; i<45; i++) { + message = session.createTextMessage(text); + producer.send(message,1,1,10); + LOG.trace("Sent message: "+ message.getJMSMessageID() + + " with expiry 10 msec"); + } + // Produce msgs that don't expire + for (int i=0; i<60; i++) { + message = session.createTextMessage(text); + producer.send(message,1,1,30000); + // producer.send(message); + LOG.trace("Sent message: "+ message.getJMSMessageID() + + " with expiry 30 sec"); + } + sleep(200); + + int counter = 1; + for (; counter <= 60; ++counter) { + assertNotNull(consumer.receive(2000)); + LOG.info("counter at " + counter); + } + LOG.info("Received all expected messages with counter at: " + counter); + + // Cleanup + producer.close(); + consumer.close(); + session.close(); + connection.close(); + } + + @Test + public void testOptimizedAckWithExpiredMsgsSync2() throws Exception + { + ActiveMQConnectionFactory connectionFactory = + new ActiveMQConnectionFactory(connectionUri + "?jms.optimizeAcknowledge=true&jms.prefetchPolicy.all=100"); + + // Create JMS resources + Connection connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue("TEST.FOO"); + + // ***** Consumer code ***** + MessageConsumer consumer = session.createConsumer(destination); + + // ***** Producer Code ***** + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode(); + TextMessage message; + + // Produce msgs that don't expire + for (int i=0; i<56; i++) { + message = session.createTextMessage(text); + producer.send(message,1,1,30000); + // producer.send(message); + LOG.trace("Sent message: "+ message.getJMSMessageID() + + " with expiry 30 sec"); + } + // Produce msgs that will expire quickly + for (int i=0; i<44; i++) { + message = session.createTextMessage(text); + producer.send(message,1,1,10); + LOG.trace("Sent message: "+ message.getJMSMessageID() + + " with expiry 10 msec"); + } + // Produce some moremsgs that don't expire + for (int i=0; i<4; i++) { + message = session.createTextMessage(text); + producer.send(message,1,1,30000); + // producer.send(message); + LOG.trace("Sent message: "+ message.getJMSMessageID() + + " with expiry 30 sec"); + } + + sleep(200); + + int counter = 1; + for (; counter <= 60; ++counter) { + assertNotNull(consumer.receive(2000)); + LOG.info("counter at " + counter); + } + LOG.info("Received all expected messages with counter at: " + counter); + + // Cleanup + producer.close(); + consumer.close(); + session.close(); + connection.close(); + } + + private void sleep(int milliSecondTime) { + try { + Thread.sleep(milliSecondTime); + } catch (InterruptedException igonred) { + } + } + + /** + * Standard JMS MessageListener + */ + private class MyMessageListener implements MessageListener, ExceptionListener { + + private AtomicInteger counter = new AtomicInteger(0); + + public void onMessage(final Message message) { + try { + LOG.trace("Got Message " + message.getJMSMessageID()); + LOG.info("counter at " + counter.incrementAndGet()); + } catch (final Exception e) { + } + } + + public int getCounter() { + return counter.get(); + } + + public synchronized void onException(JMSException ex) { + LOG.error("JMS Exception occured. Shutting down client."); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/OutOfOrderTestCase.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/OutOfOrderTestCase.java new file mode 100644 index 0000000000..34e3866749 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/OutOfOrderTestCase.java @@ -0,0 +1,131 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OutOfOrderTestCase extends TestCase { + + private static final Logger log = LoggerFactory.getLogger(OutOfOrderTestCase.class); + + private static final String BROKER_URL = "tcp://localhost:0"; + private static final int PREFETCH = 10; + private static final String CONNECTION_URL_OPTIONS = "?jms.prefetchPolicy.all=" + PREFETCH; + + private static final String DESTINATION = "QUEUE?consumer.exclusive=true"; + + private BrokerService brokerService; + private Session session; + private Connection connection; + private String connectionUri; + + private int seq = 0; + + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setUseJmx(true); + brokerService.addConnector(BROKER_URL); + brokerService.deleteAllMessages(); + brokerService.start(); + brokerService.waitUntilStarted(); + + connectionUri = brokerService.getTransportConnectors().get(0).getPublishableConnectString(); + + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionUri + CONNECTION_URL_OPTIONS); + connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + } + + protected void tearDown() throws Exception { + session.close(); + connection.close(); + brokerService.stop(); + } + + public void testOrder() throws Exception { + + log.info("Producing messages 0-29 . . ."); + Destination destination = session.createQueue(DESTINATION); + final MessageProducer messageProducer = session + .createProducer(destination); + try { + for (int i = 0; i < 30; ++i) { + final Message message = session + .createTextMessage(createMessageText(i)); + message.setStringProperty("JMSXGroupID", "FOO"); + + messageProducer.send(message); + log.info("sent " + toString(message)); + } + } finally { + messageProducer.close(); + } + + log.info("Consuming messages 0-9 . . ."); + consumeBatch(); + + log.info("Consuming messages 10-19 . . ."); + consumeBatch(); + + log.info("Consuming messages 20-29 . . ."); + consumeBatch(); + } + + protected void consumeBatch() throws Exception { + Destination destination = session.createQueue(DESTINATION); + final MessageConsumer messageConsumer = session.createConsumer(destination); + try { + for (int i = 0; i < 10; ++i) { + final Message message = messageConsumer.receive(1000L); + log.info("received " + toString(message)); + assertEquals("Message out of order", createMessageText(seq++), ((TextMessage) message).getText()); + message.acknowledge(); + } + } finally { + messageConsumer.close(); + } + } + + private String toString(final Message message) throws JMSException { + String ret = "received message '" + ((TextMessage) message).getText() + "' - " + message.getJMSMessageID(); + if (message.getJMSRedelivered()) + ret += " (redelivered)"; + return ret; + + } + + private static String createMessageText(final int index) { + return "message #" + index; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/QueueWorkerPrefetchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/QueueWorkerPrefetchTest.java new file mode 100644 index 0000000000..80adaed328 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/QueueWorkerPrefetchTest.java @@ -0,0 +1,248 @@ +/** + * 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.bugs; + +import java.io.Serializable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.Session; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test case demonstrating situation where messages are not delivered to + * consumers. + */ +public class QueueWorkerPrefetchTest extends TestCase implements + MessageListener { + private static final Logger LOG = LoggerFactory + .getLogger(QueueWorkerPrefetchTest.class); + private static final int BATCH_SIZE = 10; + private static final long WAIT_TIMEOUT = 1000 * 10; + + /** The connection URL. */ + private static final String BROKER_BIND_ADDRESS = "tcp://localhost:0"; + + /** + * The queue prefetch size to use. A value greater than 1 seems to make + * things work. + */ + private static final int QUEUE_PREFETCH_SIZE = 1; + + /** + * The number of workers to use. A single worker with a prefetch of 1 works. + */ + private static final int NUM_WORKERS = 2; + + /** Embedded JMS broker. */ + private BrokerService broker; + + /** The master's producer object for creating work items. */ + private MessageProducer workItemProducer; + + /** The master's consumer object for consuming ack messages from workers. */ + private MessageConsumer masterItemConsumer; + + /** The number of acks received by the master. */ + private final AtomicLong acksReceived = new AtomicLong(0); + + private final AtomicReference latch = new AtomicReference(); + + private String connectionUri; + + /** Messages sent to the work-item queue. */ + private static class WorkMessage implements Serializable { + private static final long serialVersionUID = 1L; + private final int id; + + public WorkMessage(int id) { + this.id = id; + } + + @Override + public String toString() { + return "Work: " + id; + } + } + + /** + * The worker process. Consume messages from the work-item queue, possibly + * creating more messages to submit to the work-item queue. For each work + * item, send an ack to the master. + */ + private static class Worker implements MessageListener { + /** + * Counter shared between workers to decided when new work-item messages + * are created. + */ + private static AtomicInteger counter = new AtomicInteger(0); + + /** Session to use. */ + private Session session; + + /** Producer for sending ack messages to the master. */ + private MessageProducer masterItemProducer; + + /** Producer for sending new work items to the work-items queue. */ + private MessageProducer workItemProducer; + + public Worker(Session session) throws JMSException { + this.session = session; + masterItemProducer = session.createProducer(session + .createQueue("master-item")); + Queue workItemQueue = session.createQueue("work-item"); + workItemProducer = session.createProducer(workItemQueue); + MessageConsumer workItemConsumer = session + .createConsumer(workItemQueue); + workItemConsumer.setMessageListener(this); + } + + public void onMessage(javax.jms.Message message) { + try { + WorkMessage work = (WorkMessage) ((ObjectMessage) message) + .getObject(); + + long c = counter.incrementAndGet(); + + // Don't create a new work item for every BATCH_SIZE message. */ + if (c % BATCH_SIZE != 0) { + // Send new work item to work-item queue. + workItemProducer.send(session + .createObjectMessage(new WorkMessage(work.id + 1))); + } + + // Send ack to master. + masterItemProducer.send(session.createObjectMessage(work)); + } catch (JMSException e) { + throw new IllegalStateException("Something has gone wrong", e); + } + } + + /** Close of JMS resources used by worker. */ + public void close() throws JMSException { + masterItemProducer.close(); + workItemProducer.close(); + session.close(); + } + } + + /** Master message handler. Process ack messages. */ + public void onMessage(javax.jms.Message message) { + long acks = acksReceived.incrementAndGet(); + latch.get().countDown(); + if (acks % 1 == 0) { + LOG.info("Master now has ack count of: " + acksReceived); + } + } + + protected void setUp() throws Exception { + // Create the message broker. + super.setUp(); + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.addConnector(BROKER_BIND_ADDRESS); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + protected void tearDown() throws Exception { + // Shut down the message broker. + broker.deleteAllMessages(); + broker.stop(); + super.tearDown(); + } + + public void testActiveMQ() throws Exception { + // Create the connection to the broker. + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionUri); + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setQueuePrefetch(QUEUE_PREFETCH_SIZE); + connectionFactory.setPrefetchPolicy(prefetchPolicy); + Connection connection = connectionFactory.createConnection(); + connection.start(); + + Session masterSession = connection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + workItemProducer = masterSession.createProducer(masterSession + .createQueue("work-item")); + masterItemConsumer = masterSession.createConsumer(masterSession + .createQueue("master-item")); + masterItemConsumer.setMessageListener(this); + + // Create the workers. + Worker[] workers = new Worker[NUM_WORKERS]; + for (int i = 0; i < NUM_WORKERS; i++) { + workers[i] = new Worker(connection.createSession(false, + Session.AUTO_ACKNOWLEDGE)); + } + + // Send a message to the work queue, and wait for the BATCH_SIZE acks + // from the workers. + acksReceived.set(0); + latch.set(new CountDownLatch(BATCH_SIZE)); + workItemProducer.send(masterSession + .createObjectMessage(new WorkMessage(1))); + + if (!latch.get().await(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { + fail("First batch only received " + acksReceived + " messages"); + } + + LOG.info("First batch received"); + + // Send another message to the work queue, and wait for the next 1000 acks. It is + // at this point where the workers never get notified of this message, as they + // have a large pending queue. Creating a new worker at this point however will + // receive this new message. + acksReceived.set(0); + latch.set(new CountDownLatch(BATCH_SIZE)); + workItemProducer.send(masterSession + .createObjectMessage(new WorkMessage(1))); + + if (!latch.get().await(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { + fail("Second batch only received " + acksReceived + " messages"); + } + + LOG.info("Second batch received"); + + // Cleanup all JMS resources. + for (int i = 0; i < NUM_WORKERS; i++) { + workers[i].close(); + } + masterSession.close(); + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RawRollbackSharedConsumerTests.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RawRollbackSharedConsumerTests.java new file mode 100644 index 0000000000..4790e42aaa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RawRollbackSharedConsumerTests.java @@ -0,0 +1,134 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RawRollbackSharedConsumerTests { + + private static ConnectionFactory connectionFactory; + private static Destination queue; + private static BrokerService broker; + + @BeforeClass + public static void clean() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setUseJmx(true); + broker.start(); + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); + connectionFactory.setBrokerURL("vm://localhost?async=false"); + RawRollbackSharedConsumerTests.connectionFactory = connectionFactory; + queue = new ActiveMQQueue("queue"); + } + + @AfterClass + public static void close() throws Exception { + broker.stop(); + } + + @Before + public void clearData() throws Exception { + getMessages(false); // drain queue + convertAndSend("foo"); + convertAndSend("bar"); + } + + + @After + public void checkPostConditions() throws Exception { + + Thread.sleep(1000L); + List list = getMessages(false); + assertEquals(2, list.size()); + + } + + @Test + public void testReceiveMessages() throws Exception { + + List list = getMessages(true); + assertEquals(2, list.size()); + assertTrue(list.contains("foo")); + + } + + private void convertAndSend(String msg) throws Exception { + Connection connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage(msg)); + producer.close(); + session.commit(); + session.close(); + connection.close(); + } + + private List getMessages(boolean rollback) throws Exception { + Connection connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + String next = ""; + List msgs = new ArrayList(); + MessageConsumer consumer = session.createConsumer(queue); + while (next != null) { + next = (String) receiveAndConvert(consumer); + if (next != null) + msgs.add(next); + } + consumer.close(); + if (rollback) { + session.rollback(); + } else { + session.commit(); + } + session.close(); + connection.close(); + return msgs; + } + + private String receiveAndConvert(MessageConsumer consumer) throws Exception { + Message message = consumer.receive(100L); + if (message==null) { + return null; + } + return ((TextMessage)message).getText(); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RawRollbackTests.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RawRollbackTests.java new file mode 100644 index 0000000000..93abb28fa0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RawRollbackTests.java @@ -0,0 +1,135 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RawRollbackTests { + + private static ConnectionFactory connectionFactory; + private static Destination queue; + private static BrokerService broker; + + @BeforeClass + public static void clean() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setUseJmx(true); + broker.start(); + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); + connectionFactory.setBrokerURL("vm://localhost?async=false&waitForStart=5000&jms.prefetchPolicy.all=0"); + RawRollbackTests.connectionFactory = connectionFactory; + queue = new ActiveMQQueue("queue"); + } + + @AfterClass + public static void close() throws Exception { + broker.stop(); + } + + @Before + public void clearData() throws Exception { + getMessages(false); // drain queue + convertAndSend("foo"); + convertAndSend("bar"); + } + + + @After + public void checkPostConditions() throws Exception { + + Thread.sleep(1000L); + List list = getMessages(false); + assertEquals(2, list.size()); + + } + + @Test + public void testReceiveMessages() throws Exception { + + List list = getMessages(true); + assertEquals(2, list.size()); + assertTrue(list.contains("foo")); + + } + + private void convertAndSend(String msg) throws Exception { + Connection connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage(msg)); + producer.close(); + session.commit(); + session.close(); + connection.close(); + } + + private List getMessages(boolean rollback) throws Exception { + Connection connection = connectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + String next = ""; + List msgs = new ArrayList(); + while (next != null) { + next = (String) receiveAndConvert(session); + if (next != null) + msgs.add(next); + } + if (rollback) { + session.rollback(); + } else { + session.commit(); + } + session.close(); + connection.close(); + return msgs; + } + + private String receiveAndConvert(Session session) throws Exception { + MessageConsumer consumer = session.createConsumer(queue); + Message message = consumer.receive(100L); + consumer.close(); + if (message==null) { + return null; + } + return ((TextMessage)message).getText(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/Receiver.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/Receiver.java new file mode 100644 index 0000000000..65f30e3337 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/Receiver.java @@ -0,0 +1,21 @@ +/** + * 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.bugs; + +public interface Receiver { + void receive(String s) throws Exception; +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RedeliveryPluginHeaderTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RedeliveryPluginHeaderTest.java new file mode 100644 index 0000000000..414b70d7d8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/RedeliveryPluginHeaderTest.java @@ -0,0 +1,167 @@ +/** + * 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.bugs; + +import java.io.File; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.RedeliveryPolicyMap; +import org.apache.activemq.broker.util.RedeliveryPlugin; +import org.apache.activemq.util.IOHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Testing if the the broker "sends" the message as expected after the redeliveryPlugin has redelivered the + * message previously. + */ + +public class RedeliveryPluginHeaderTest extends TestCase { + + private static final String TEST_QUEUE_ONE = "TEST_QUEUE_ONE"; + private static final String TEST_QUEUE_TWO = "TEST_QUEUE_TWO"; + private static final Logger LOG = LoggerFactory + .getLogger(RedeliveryPluginHeaderTest.class); + private String transportURL; + private BrokerService broker; + + /** + * Test + * - consumes message from Queue1 + * - rolls back message to Queue1 and message is scheduled for redelivery to Queue1 by brokers plugin + * - consumes message from Queue1 again + * - sends same message to Queue2 + * - expects to consume message from Queue2 immediately + */ + + public void testSendAfterRedelivery() throws Exception { + broker = this.createBroker(false); + broker.start(); + broker.waitUntilStarted(); + + LOG.info("***Broker started..."); + + //pushed message to broker + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + transportURL + "?trace=true&jms.redeliveryPolicy.maximumRedeliveries=0"); + + Connection connection = factory.createConnection(); + connection.start(); + + try { + + Session session = connection.createSession(true, + Session.SESSION_TRANSACTED); + + Destination destinationQ1 = session.createQueue(TEST_QUEUE_ONE); + Destination destinationQ2 = session.createQueue(TEST_QUEUE_TWO); + + MessageProducer producerQ1 = session.createProducer(destinationQ1); + producerQ1.setDeliveryMode(DeliveryMode.PERSISTENT); + + Message m = session.createTextMessage("testMessage"); + LOG.info("*** send message to broker..."); + producerQ1.send(m); + session.commit(); + + //consume message from Q1 and rollback to get it redelivered + MessageConsumer consumerQ1 = session.createConsumer(destinationQ1); + + LOG.info("*** consume message from Q1 and rolled back.."); + + TextMessage textMessage = (TextMessage) consumerQ1.receive(); + LOG.info("got redelivered: " + textMessage); + assertFalse("JMSRedelivered flag is not set", textMessage.getJMSRedelivered()); + session.rollback(); + + LOG.info("*** consumed message from Q1 again and sending to Q2.."); + TextMessage textMessage2 = (TextMessage) consumerQ1.receive(); + LOG.info("got: " + textMessage2); + session.commit(); + assertTrue("JMSRedelivered flag is set", textMessage2.getJMSRedelivered()); + + //send message to Q2 and consume from Q2 + MessageConsumer consumerQ2 = session.createConsumer(destinationQ2); + MessageProducer producer_two = session.createProducer(destinationQ2); + producer_two.send(textMessage2); + session.commit(); + + //Message should be available straight away on the queue_two + Message textMessage3 = consumerQ2.receive(1000); + assertNotNull("should have consumed a message from TEST_QUEUE_TWO", textMessage3); + assertFalse("JMSRedelivered flag is not set", textMessage3.getJMSRedelivered()); + session.commit(); + + } finally { + + if (connection != null) { + connection.close(); + } + + if (broker != null) { + broker.stop(); + } + + } + + } + + protected BrokerService createBroker(boolean withJMX) throws Exception { + File schedulerDirectory = new File("target/scheduler"); + IOHelper.mkdirs(schedulerDirectory); + IOHelper.deleteChildren(schedulerDirectory); + + BrokerService answer = new BrokerService(); + answer.setAdvisorySupport(false); + answer.setDataDirectory("target"); + answer.setSchedulerDirectoryFile(schedulerDirectory); + answer.setSchedulerSupport(true); + answer.setPersistent(true); + answer.setDeleteAllMessagesOnStartup(true); + answer.setUseJmx(withJMX); + + RedeliveryPlugin redeliveryPlugin = new RedeliveryPlugin(); + RedeliveryPolicyMap redeliveryPolicyMap = new RedeliveryPolicyMap(); + RedeliveryPolicy defaultEntry = new RedeliveryPolicy(); + defaultEntry.setInitialRedeliveryDelay(5000); + defaultEntry.setMaximumRedeliveries(5); + redeliveryPolicyMap.setDefaultEntry(defaultEntry); + redeliveryPlugin.setRedeliveryPolicyMap(redeliveryPolicyMap); + + answer.setPlugins(new BrokerPlugin[] {redeliveryPlugin}); + TransportConnector transportConnector = + answer.addConnector("tcp://localhost:0"); + + transportURL = transportConnector.getConnectUri().toASCIIString(); + + return answer; + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/SlowConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/SlowConsumerTest.java new file mode 100644 index 0000000000..a2c117e23c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/SlowConsumerTest.java @@ -0,0 +1,159 @@ +/** + * 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.bugs; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SlowConsumerTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(SlowConsumerTest.class); + private static final int MESSAGES_COUNT = 10000; + + private final int messageLogFrequency = 2500; + private final long messageReceiveTimeout = 10000L; + + private Socket stompSocket; + private ByteArrayOutputStream inputBuffer; + private int messagesCount; + + /** + * @param args + * @throws Exception + */ + public void testRemoveSubscriber() throws Exception { + final BrokerService broker = new BrokerService(); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setDeleteAllMessagesOnStartup(true); + + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getPublishableConnectString()); + final Connection connection = factory.createConnection(); + connection.start(); + + Thread producingThread = new Thread("Producing thread") { + public void run() { + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(new ActiveMQQueue(getDestinationName())); + for (int idx = 0; idx < MESSAGES_COUNT; ++idx) { + Message message = session.createTextMessage("" + idx); + producer.send(message); + LOG.debug("Sending: " + idx); + } + producer.close(); + session.close(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + producingThread.setPriority(Thread.MAX_PRIORITY); + producingThread.start(); + Thread.sleep(1000); + + Thread consumingThread = new Thread("Consuming thread") { + + public void run() { + try { + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(new ActiveMQQueue(getDestinationName())); + int diff = 0; + while (messagesCount != MESSAGES_COUNT) { + Message msg = consumer.receive(messageReceiveTimeout); + if (msg == null) { + LOG.warn("Got null message at count: " + messagesCount + ". Continuing..."); + break; + } + String text = ((TextMessage)msg).getText(); + int currentMsgIdx = Integer.parseInt(text); + LOG.debug("Received: " + text + " messageCount: " + messagesCount); + msg.acknowledge(); + if ((messagesCount + diff) != currentMsgIdx) { + LOG.debug("Message(s) skipped!! Should be message no.: " + messagesCount + " but got: " + currentMsgIdx); + diff = currentMsgIdx - messagesCount; + } + ++messagesCount; + if (messagesCount % messageLogFrequency == 0) { + LOG.info("Received: " + messagesCount + " messages so far"); + } + // Thread.sleep(70); + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + consumingThread.start(); + consumingThread.join(); + + assertEquals(MESSAGES_COUNT, messagesCount); + + } + + public void sendFrame(String data) throws Exception { + byte[] bytes = data.getBytes("UTF-8"); + OutputStream outputStream = stompSocket.getOutputStream(); + for (int i = 0; i < bytes.length; i++) { + outputStream.write(bytes[i]); + } + outputStream.flush(); + } + + public String receiveFrame(long timeOut) throws Exception { + stompSocket.setSoTimeout((int)timeOut); + InputStream is = stompSocket.getInputStream(); + int c = 0; + for (;;) { + c = is.read(); + if (c < 0) { + throw new IOException("socket closed."); + } else if (c == 0) { + c = is.read(); + byte[] ba = inputBuffer.toByteArray(); + inputBuffer.reset(); + return new String(ba, "UTF-8"); + } else { + inputBuffer.write(c); + } + } + } + + protected String getDestinationName() { + return getClass().getName() + "." + getName(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/SparseAckReplayAfterStoreCleanupLevelDBStoreTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/SparseAckReplayAfterStoreCleanupLevelDBStoreTest.java new file mode 100644 index 0000000000..ba15941a47 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/SparseAckReplayAfterStoreCleanupLevelDBStoreTest.java @@ -0,0 +1,30 @@ +/** + * 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.bugs; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; + + +public class SparseAckReplayAfterStoreCleanupLevelDBStoreTest extends AMQ2832Test { + @Override + protected void configurePersistence(BrokerService brokerService, boolean deleteAllOnStart) throws Exception { + LevelDBStore store = new LevelDBStore(); + store.setFlushDelay(0); + brokerService.setPersistenceAdapter(store); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempQueueDeleteOnCloseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempQueueDeleteOnCloseTest.java new file mode 100644 index 0000000000..44e7f5d8ab --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempQueueDeleteOnCloseTest.java @@ -0,0 +1,54 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.junit.Test; + +/** + * Demonstrates how unmarshalled VM advisory messages for temporary queues prevent other connections from being closed. + */ +public class TempQueueDeleteOnCloseTest { + + @Test + public void test() throws Exception { + ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + + // create a connection and session with a temporary queue + Connection connectionA = connectionFactory.createConnection(); + connectionA.setClientID("ConnectionA"); + Session sessionA = connectionA.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination tempQueueA = sessionA.createTemporaryQueue(); + MessageConsumer consumer = sessionA.createConsumer(tempQueueA); + connectionA.start(); + + // start and stop another connection + Connection connectionB = connectionFactory.createConnection(); + connectionB.setClientID("ConnectionB"); + connectionB.start(); + connectionB.close(); + + consumer.close(); + connectionA.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStorageBlockedBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStorageBlockedBrokerTest.java new file mode 100644 index 0000000000..066fb07d2b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStorageBlockedBrokerTest.java @@ -0,0 +1,266 @@ +/** + * 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.bugs; + +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ResourceAllocationException; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.plist.PListStoreImpl; +import org.apache.activemq.usage.MemoryUsage; +import org.apache.activemq.usage.StoreUsage; +import org.apache.activemq.usage.SystemUsage; +import org.apache.activemq.usage.TempUsage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TempStorageBlockedBrokerTest extends TestSupport { + + public int deliveryMode = DeliveryMode.PERSISTENT; + + private static final Logger LOG = LoggerFactory.getLogger(TempStorageBlockedBrokerTest.class); + private static final int MESSAGES_COUNT = 1000; + private static byte[] buf = new byte[4 * 1024]; + private BrokerService broker; + AtomicInteger messagesSent = new AtomicInteger(0); + AtomicInteger messagesConsumed = new AtomicInteger(0); + + protected long messageReceiveTimeout = 10000L; + + Destination destination = new ActiveMQTopic("FooTwo"); + + private String connectionUri; + + public void testRunProducerWithHungConsumer() throws Exception { + + final long origTempUsage = broker.getSystemUsage().getTempUsage().getUsage(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + // ensure messages are spooled to disk for this consumer + ActiveMQPrefetchPolicy prefetch = new ActiveMQPrefetchPolicy(); + prefetch.setTopicPrefetch(10); + factory.setPrefetchPolicy(prefetch); + Connection consumerConnection = factory.createConnection(); + consumerConnection.start(); + + Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(destination); + + final Connection producerConnection = factory.createConnection(); + producerConnection.start(); + + final CountDownLatch producerHasSentTenMessages = new CountDownLatch(10); + Thread producingThread = new Thread("Producing thread") { + @Override + public void run() { + try { + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + for (int idx = 0; idx < MESSAGES_COUNT; ++idx) { + Message message = session.createTextMessage(new String(buf) + idx); + + producer.send(message); + messagesSent.incrementAndGet(); + producerHasSentTenMessages.countDown(); + Thread.sleep(10); + if (idx != 0 && idx%100 == 0) { + LOG.info("Sent Message " + idx); + LOG.info("Temp Store Usage " + broker.getSystemUsage().getTempUsage().getUsage()); + } + } + producer.close(); + session.close(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + producingThread.start(); + + assertTrue("producer has sent 10 in a reasonable time", producerHasSentTenMessages.await(30, TimeUnit.SECONDS)); + + int count = 0; + + Message m = null; + while ((m = consumer.receive(messageReceiveTimeout)) != null) { + count++; + if (count != 0 && count%10 == 0) { + LOG.info("Recieved Message (" + count + "):" + m); + } + messagesConsumed.incrementAndGet(); + try { + Thread.sleep(100); + } catch (Exception e) { + LOG.info("error sleeping"); + } + } + + LOG.info("Connection Timeout: Retrying.. count: " + count); + + while ((m = consumer.receive(messageReceiveTimeout)) != null) { + count++; + if (count != 0 && count%100 == 0) { + LOG.info("Recieved Message (" + count + "):" + m); + } + messagesConsumed.incrementAndGet(); + try { + Thread.sleep(100); + } catch (Exception e) { + LOG.info("error sleeping"); + } + } + + LOG.info("consumer session closing: consumed count: " + count); + + consumerSession.close(); + + producingThread.join(); + + final long tempUsageBySubscription = broker.getSystemUsage().getTempUsage().getUsage(); + LOG.info("Orig Usage: " + origTempUsage + ", currentUsage: " + tempUsageBySubscription); + + producerConnection.close(); + consumerConnection.close(); + + LOG.info("Subscrition Usage: " + tempUsageBySubscription + ", endUsage: " + + broker.getSystemUsage().getTempUsage().getUsage()); + + // do a cleanup + ((PListStoreImpl)broker.getTempDataStore()).run(); + LOG.info("Subscrition Usage: " + tempUsageBySubscription + ", endUsage: " + + broker.getSystemUsage().getTempUsage().getUsage()); + + assertEquals("Incorrect number of Messages Sent: " + messagesSent.get(), messagesSent.get(), MESSAGES_COUNT); + assertEquals("Incorrect number of Messages Consumed: " + messagesConsumed.get(), messagesConsumed.get(), + MESSAGES_COUNT); + } + + public void testFillTempAndConsume() throws Exception { + + broker.getSystemUsage().setSendFailIfNoSpace(true); + destination = new ActiveMQQueue("Foo"); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + final ActiveMQConnection producerConnection = (ActiveMQConnection) factory.createConnection(); + // so we can easily catch the ResourceAllocationException on send + producerConnection.setAlwaysSyncSend(true); + producerConnection.start(); + + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + try { + while (true) { + Message message = session.createTextMessage(new String(buf) + messagesSent.toString()); + producer.send(message); + messagesSent.incrementAndGet(); + if (messagesSent.get() % 100 == 0) { + LOG.info("Sent Message " + messagesSent.get()); + LOG.info("Temp Store Usage " + broker.getSystemUsage().getTempUsage().getUsage()); + } + } + } catch (ResourceAllocationException ex) { + LOG.info("Got resource exception : " + ex + ", after sent: " + messagesSent.get()); + } + + // consume all sent + Connection consumerConnection = factory.createConnection(); + consumerConnection.start(); + + Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(destination); + + + while (consumer.receive(messageReceiveTimeout) != null) { + messagesConsumed.incrementAndGet(); + if (messagesConsumed.get() % 1000 == 0) { + LOG.info("received Message " + messagesConsumed.get()); + LOG.info("Temp Store Usage " + broker.getSystemUsage().getTempUsage().getUsage()); + } + } + + assertEquals("Incorrect number of Messages Consumed: " + messagesConsumed.get(), messagesConsumed.get(), + messagesSent.get()); + } + + @Override + public void setUp() throws Exception { + + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + + setDefaultPersistenceAdapter(broker); + SystemUsage sysUsage = broker.getSystemUsage(); + MemoryUsage memUsage = new MemoryUsage(); + memUsage.setLimit((1024 * 1024)); + StoreUsage storeUsage = new StoreUsage(); + storeUsage.setLimit((1024 * 1024) * 38); + TempUsage tmpUsage = new TempUsage(); + tmpUsage.setLimit((1024 * 1024) * 38); + + PolicyEntry defaultPolicy = new PolicyEntry(); + // defaultPolicy.setTopic("FooTwo"); + defaultPolicy.setProducerFlowControl(false); + defaultPolicy.setMemoryLimit(10 * 1024); + + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultPolicy); + + sysUsage.setMemoryUsage(memUsage); + sysUsage.setStoreUsage(storeUsage); + sysUsage.setTempUsage(tmpUsage); + + broker.setDestinationPolicy(policyMap); + broker.setSystemUsage(sysUsage); + + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + @Override + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStorageConfigBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStorageConfigBrokerTest.java new file mode 100644 index 0000000000..1061346c1a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStorageConfigBrokerTest.java @@ -0,0 +1,220 @@ +/** + * 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.bugs; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ResourceAllocationException; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.plist.PListStoreImpl; +import org.junit.After; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test that when configuring small temp store limits the journal size must also + * be smaller than the configured limit, but will still send a ResourceAllocationException + * if its not when sendFailIfNoSpace is enabled. + */ +public class TempStorageConfigBrokerTest { + + public int deliveryMode = DeliveryMode.PERSISTENT; + + private static final Logger LOG = LoggerFactory.getLogger(TempStorageConfigBrokerTest.class); + private static byte[] buf = new byte[4 * 1024]; + private BrokerService broker; + private AtomicInteger messagesSent = new AtomicInteger(0); + private AtomicInteger messagesConsumed = new AtomicInteger(0); + + private String brokerUri; + private long messageReceiveTimeout = 10000L; + private Destination destination = new ActiveMQTopic("FooTwo"); + + @Test(timeout=360000) + @Ignore("blocks in hudson, needs investigation") + public void testFillTempAndConsumeWithBadTempStoreConfig() throws Exception { + + createBrokerWithInvalidTempStoreConfig(); + + broker.getSystemUsage().setSendFailIfNoSpace(true); + destination = new ActiveMQQueue("Foo"); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUri); + final ActiveMQConnection producerConnection = (ActiveMQConnection) factory.createConnection(); + // so we can easily catch the ResourceAllocationException on send + producerConnection.setAlwaysSyncSend(true); + producerConnection.start(); + + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + try { + while (true) { + Message message = session.createTextMessage(new String(buf) + messagesSent.toString()); + producer.send(message); + messagesSent.incrementAndGet(); + if (messagesSent.get() % 100 == 0) { + LOG.info("Sent Message " + messagesSent.get()); + LOG.info("Temp Store Usage " + broker.getSystemUsage().getTempUsage().getUsage()); + } + } + } catch (ResourceAllocationException ex) { + assertTrue("Should not be able to send 100 messages: ", messagesSent.get() < 100); + LOG.info("Got resource exception : " + ex + ", after sent: " + messagesSent.get()); + } + } + + @Test(timeout=360000) + @Ignore("blocks in hudson, needs investigation") + public void testFillTempAndConsumeWithGoodTempStoreConfig() throws Exception { + + createBrokerWithValidTempStoreConfig(); + + broker.getSystemUsage().setSendFailIfNoSpace(true); + destination = new ActiveMQQueue("Foo"); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUri); + final ActiveMQConnection producerConnection = (ActiveMQConnection) factory.createConnection(); + // so we can easily catch the ResourceAllocationException on send + producerConnection.setAlwaysSyncSend(true); + producerConnection.start(); + + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + try { + while (true) { + Message message = session.createTextMessage(new String(buf) + messagesSent.toString()); + producer.send(message); + messagesSent.incrementAndGet(); + if (messagesSent.get() % 100 == 0) { + LOG.info("Sent Message " + messagesSent.get()); + LOG.info("Temp Store Usage " + broker.getSystemUsage().getTempUsage().getUsage()); + } + } + } catch (ResourceAllocationException ex) { + assertTrue("Should be able to send at least 200 messages but was: " + messagesSent.get(), + messagesSent.get() > 200); + LOG.info("Got resource exception : " + ex + ", after sent: " + messagesSent.get()); + } + + // consume all sent + Connection consumerConnection = factory.createConnection(); + consumerConnection.start(); + + Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(destination); + + while (consumer.receive(messageReceiveTimeout) != null) { + messagesConsumed.incrementAndGet(); + if (messagesConsumed.get() % 1000 == 0) { + LOG.info("received Message " + messagesConsumed.get()); + LOG.info("Temp Store Usage " + broker.getSystemUsage().getTempUsage().getUsage()); + } + } + + assertEquals("Incorrect number of Messages Consumed: " + messagesConsumed.get(), + messagesConsumed.get(), messagesSent.get()); + } + + private void createBrokerWithValidTempStoreConfig() throws Exception { + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistenceAdapter(new KahaDBPersistenceAdapter()); + + broker.getSystemUsage().setSendFailIfNoSpace(true); + broker.getSystemUsage().getMemoryUsage().setLimit(1048576); + broker.getSystemUsage().getTempUsage().setLimit(2*1048576); + ((PListStoreImpl)broker.getSystemUsage().getTempUsage().getStore()).setJournalMaxFileLength(2 * 1048576); + broker.getSystemUsage().getStoreUsage().setLimit(20*1048576); + + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setProducerFlowControl(false); + defaultPolicy.setMemoryLimit(10 * 1024); + + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultPolicy); + + broker.setDestinationPolicy(policyMap); + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + + brokerUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + private void createBrokerWithInvalidTempStoreConfig() throws Exception { + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistenceAdapter(new KahaDBPersistenceAdapter()); + + broker.getSystemUsage().setSendFailIfNoSpace(true); + broker.getSystemUsage().getMemoryUsage().setLimit(1048576); + broker.getSystemUsage().getTempUsage().setLimit(2*1048576); + broker.getSystemUsage().getStoreUsage().setLimit(2*1048576); + + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setProducerFlowControl(false); + defaultPolicy.setMemoryLimit(10 * 1024); + + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultPolicy); + + broker.setDestinationPolicy(policyMap); + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + + brokerUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStoreDataCleanupTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStoreDataCleanupTest.java new file mode 100644 index 0000000000..34df4a3d65 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TempStoreDataCleanupTest.java @@ -0,0 +1,261 @@ +/** + * 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.bugs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.plist.PListStoreImpl; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TempStoreDataCleanupTest { + + private static final Logger LOG = LoggerFactory.getLogger(TempStoreDataCleanupTest.class); + private static final String QUEUE_NAME = TempStoreDataCleanupTest.class.getName() + "Queue"; + + private final String str = new String( + "QAa0bcLdUK2eHfJgTP8XhiFj61DOklNm9nBoI5pGqYVrs3CtSuMZvwWx4yE7zR"); + + private BrokerService broker; + private String connectionUri; + private ExecutorService pool; + private String queueName; + private Random r = new Random(); + + @Before + public void setUp() throws Exception { + + broker = new BrokerService(); + broker.setDataDirectory("target" + File.separator + "activemq-data"); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.setDedicatedTaskRunner(false); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(true); + + SharedDeadLetterStrategy strategy = new SharedDeadLetterStrategy(); + strategy.setProcessExpired(false); + strategy.setProcessNonPersistent(false); + + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setQueue(">"); + defaultPolicy.setOptimizedDispatch(true); + defaultPolicy.setDeadLetterStrategy(strategy); + defaultPolicy.setMemoryLimit(9000000); + + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultPolicy); + + broker.setDestinationPolicy(policyMap); + + broker.getSystemUsage().getMemoryUsage().setLimit(300000000L); + + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + pool = Executors.newFixedThreadPool(10); + } + + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + + if (pool != null) { + pool.shutdown(); + } + } + + @Test + public void testIt() throws Exception { + + int startPercentage = broker.getAdminView().getMemoryPercentUsage(); + LOG.info("MemoryUsage at test start = " + startPercentage); + + for (int i = 0; i < 2; i++) { + LOG.info("Started the test iteration: " + i + " using queueName = " + queueName); + queueName = QUEUE_NAME + i; + final CountDownLatch latch = new CountDownLatch(11); + + pool.execute(new Runnable() { + @Override + public void run() { + receiveAndDiscard100messages(latch); + } + }); + + for (int j = 0; j < 10; j++) { + pool.execute(new Runnable() { + @Override + public void run() { + send10000messages(latch); + } + }); + } + + LOG.info("Waiting on the send / receive latch"); + latch.await(5, TimeUnit.MINUTES); + LOG.info("Resumed"); + + destroyQueue(); + TimeUnit.SECONDS.sleep(2); + } + + LOG.info("MemoryUsage before awaiting temp store cleanup = " + broker.getAdminView().getMemoryPercentUsage()); + + final PListStoreImpl pa = (PListStoreImpl) broker.getTempDataStore(); + assertTrue("only one journal file should be left: " + pa.getJournal().getFileMap().size(), + Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return pa.getJournal().getFileMap().size() == 1; + } + }, TimeUnit.MINUTES.toMillis(3)) + ); + + int endPercentage = broker.getAdminView().getMemoryPercentUsage(); + LOG.info("MemoryUseage at test end = " + endPercentage); + + assertEquals(startPercentage, endPercentage); + } + + public void destroyQueue() { + try { + Broker broker = this.broker.getBroker(); + if (!broker.isStopped()) { + LOG.info("Removing: " + queueName); + broker.removeDestination(this.broker.getAdminConnectionContext(), new ActiveMQQueue(queueName), 10); + } + } catch (Exception e) { + LOG.warn("Got an error while removing the test queue", e); + } + } + + private void send10000messages(CountDownLatch latch) { + ActiveMQConnection activeMQConnection = null; + try { + activeMQConnection = createConnection(null); + Session session = activeMQConnection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session + .createQueue(queueName)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + activeMQConnection.start(); + for (int i = 0; i < 10000; i++) { + TextMessage textMessage = session.createTextMessage(); + textMessage.setText(generateBody(1000)); + textMessage.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(textMessage); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + producer.close(); + } catch (JMSException e) { + LOG.warn("Got an error while sending the messages", e); + } finally { + if (activeMQConnection != null) { + try { + activeMQConnection.close(); + } catch (JMSException e) { + } + } + } + latch.countDown(); + } + + private void receiveAndDiscard100messages(CountDownLatch latch) { + ActiveMQConnection activeMQConnection = null; + try { + activeMQConnection = createConnection(null); + Session session = activeMQConnection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + MessageConsumer messageConsumer = session.createConsumer( + session.createQueue(queueName)); + activeMQConnection.start(); + for (int i = 0; i < 100; i++) { + messageConsumer.receive(); + } + messageConsumer.close(); + LOG.info("Created and disconnected"); + } catch (JMSException e) { + LOG.warn("Got an error while receiving the messages", e); + } finally { + if (activeMQConnection != null) { + try { + activeMQConnection.close(); + } catch (JMSException e) { + } + } + } + latch.countDown(); + } + + private ActiveMQConnection createConnection(String id) throws JMSException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + if (id != null) { + factory.setClientID(id); + } + + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + return connection; + } + + private String generateBody(int length) { + + StringBuilder sb = new StringBuilder(); + int te = 0; + for (int i = 1; i <= length; i++) { + te = r.nextInt(62); + sb.append(str.charAt(te)); + } + return sb.toString(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TransactedStoreUsageSuspendResumeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TransactedStoreUsageSuspendResumeTest.java new file mode 100644 index 0000000000..3d32867ff7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TransactedStoreUsageSuspendResumeTest.java @@ -0,0 +1,193 @@ +/** + * 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.bugs; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertTrue; + +// https://issues.apache.org/jira/browse/AMQ-4262 +public class TransactedStoreUsageSuspendResumeTest { + private static final Logger LOG = LoggerFactory.getLogger(TransactedStoreUsageSuspendResumeTest.class); + + private static final int MAX_MESSAGES = 10000; + + private static final String QUEUE_NAME = "test.queue"; + + private BrokerService broker; + + private final CountDownLatch messagesReceivedCountDown = new CountDownLatch(MAX_MESSAGES); + private final CountDownLatch messagesSentCountDown = new CountDownLatch(MAX_MESSAGES); + private final CountDownLatch consumerStartLatch = new CountDownLatch(1); + + private class ConsumerThread extends Thread { + + @Override + public void run() { + try { + + consumerStartLatch.await(30, TimeUnit.SECONDS); + + ConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + + // wait for producer to stop + long currentSendCount; + do { + currentSendCount = messagesSentCountDown.getCount(); + TimeUnit.SECONDS.sleep(5); + } while (currentSendCount != messagesSentCountDown.getCount()); + + LOG.info("Starting consumer at: " + currentSendCount); + + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + + do { + Message message = consumer.receive(5000); + if (message != null) { + session.commit(); + messagesReceivedCountDown.countDown(); + } + if (messagesReceivedCountDown.getCount() % 500 == 0) { + LOG.info("remaining to receive: " + messagesReceivedCountDown.getCount()); + } + } while (messagesReceivedCountDown.getCount() != 0); + consumer.close(); + session.close(); + connection.close(); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + } + + @Before + public void setup() throws Exception { + + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(true); + + KahaDBPersistenceAdapter kahaDB = new KahaDBPersistenceAdapter(); + kahaDB.setJournalMaxFileLength(500 * 1024); + kahaDB.setCleanupInterval(10*1000); + broker.setPersistenceAdapter(kahaDB); + + broker.getSystemUsage().getStoreUsage().setLimit(7*1024*1024); + + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + broker.stop(); + } + + @Test + public void testTransactedStoreUsageSuspendResume() throws Exception { + + ConsumerThread thread = new ConsumerThread(); + thread.start(); + ExecutorService sendExecutor = Executors.newSingleThreadExecutor(); + sendExecutor.execute(new Runnable() { + @Override + public void run() { + try { + sendMessages(); + } catch (Exception ignored) { + } + } + }); + sendExecutor.shutdown(); + sendExecutor.awaitTermination(5, TimeUnit.MINUTES); + + boolean allMessagesReceived = messagesReceivedCountDown.await(10, TimeUnit.MINUTES); + if (!allMessagesReceived) { + TestSupport.dumpAllThreads("StuckConsumer!"); + } + assertTrue("Got all messages: " + messagesReceivedCountDown, allMessagesReceived); + + // give consumers a chance to exit gracefully + TimeUnit.SECONDS.sleep(2); + } + + private void sendMessages() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setAlwaysSyncSend(true); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination queue = session.createQueue(QUEUE_NAME); + Destination retainQueue = session.createQueue(QUEUE_NAME + "-retain"); + MessageProducer producer = session.createProducer(null); + + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + BytesMessage message = session.createBytesMessage(); + message.writeBytes(new byte[10]); + + for (int i=0; i<4240; i++) { + // mostly fill the store with retained messages + // so consumer only has a small bit of store usage to work with + producer.send(retainQueue, message); + session.commit(); + } + + consumerStartLatch.countDown(); + for (int i = 0; i < MAX_MESSAGES; i++) { + producer.send(queue, message); + if (i>0 && i%20 == 0) { + session.commit(); + } + messagesSentCountDown.countDown(); + if (i>0 && i%500 == 0) { + LOG.info("Sent : " + i); + } + + } + session.commit(); + producer.close(); + session.close(); + connection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TransactionNotStartedErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TransactionNotStartedErrorTest.java new file mode 100644 index 0000000000..1baff9a709 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TransactionNotStartedErrorTest.java @@ -0,0 +1,284 @@ +/** + * 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.bugs; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.ObjectMessage; +import javax.jms.Session; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * simulate message flow which cause the following exception in the broker + * (exception logged by client)

2007-07-24 13:51:23,624 + * com.easynet.halo.Halo ERROR (LoggingErrorHandler.java: 23) JMS failure + * javax.jms.JMSException: Transaction 'TX:ID:dmt-53625-1185281414694-1:0:344' + * has not been started. at + * org.apache.activemq.broker.TransactionBroker.getTransaction(TransactionBroker.java:230) + * This appears to be consistent in a MacBook. Haven't been able to replicate it + * on Windows though + */ +public class TransactionNotStartedErrorTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(TransactionNotStartedErrorTest.class); + + private static final int counter = 500; + + private static int hectorToHaloCtr; + private static int xenaToHaloCtr; + private static int troyToHaloCtr; + + private static int haloToHectorCtr; + private static int haloToXenaCtr; + private static int haloToTroyCtr; + + private final String hectorToHalo = "hectorToHalo"; + private final String xenaToHalo = "xenaToHalo"; + private final String troyToHalo = "troyToHalo"; + + private final String haloToHector = "haloToHector"; + private final String haloToXena = "haloToXena"; + private final String haloToTroy = "haloToTroy"; + + private BrokerService broker; + + private Connection hectorConnection; + private Connection xenaConnection; + private Connection troyConnection; + private Connection haloConnection; + + private final Object lock = new Object(); + + public Connection createConnection() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getPublishableConnectString()); + return factory.createConnection(); + } + + public Session createSession(Connection connection, boolean transacted) throws JMSException { + return connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE); + } + + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + LOG.info("Starting broker.."); + } + + public void tearDown() throws Exception { + hectorConnection.close(); + xenaConnection.close(); + troyConnection.close(); + haloConnection.close(); + broker.stop(); + } + + public void testTransactionNotStartedError() throws Exception { + startBroker(); + hectorConnection = createConnection(); + Thread hectorThread = buildProducer(hectorConnection, hectorToHalo); + Receiver hHectorReceiver = new Receiver() { + public void receive(String s) throws Exception { + haloToHectorCtr++; + if (haloToHectorCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + }; + buildReceiver(hectorConnection, haloToHector, false, hHectorReceiver); + + troyConnection = createConnection(); + Thread troyThread = buildProducer(troyConnection, troyToHalo); + Receiver hTroyReceiver = new Receiver() { + public void receive(String s) throws Exception { + haloToTroyCtr++; + if (haloToTroyCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + }; + buildReceiver(hectorConnection, haloToTroy, false, hTroyReceiver); + + xenaConnection = createConnection(); + Thread xenaThread = buildProducer(xenaConnection, xenaToHalo); + Receiver hXenaReceiver = new Receiver() { + public void receive(String s) throws Exception { + haloToXenaCtr++; + if (haloToXenaCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + }; + buildReceiver(xenaConnection, haloToXena, false, hXenaReceiver); + + haloConnection = createConnection(); + final MessageSender hectorSender = buildTransactionalProducer(haloToHector, haloConnection); + final MessageSender troySender = buildTransactionalProducer(haloToTroy, haloConnection); + final MessageSender xenaSender = buildTransactionalProducer(haloToXena, haloConnection); + Receiver hectorReceiver = new Receiver() { + public void receive(String s) throws Exception { + hectorToHaloCtr++; + troySender.send("halo to troy because of hector"); + if (hectorToHaloCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + }; + Receiver xenaReceiver = new Receiver() { + public void receive(String s) throws Exception { + xenaToHaloCtr++; + hectorSender.send("halo to hector because of xena"); + if (xenaToHaloCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + }; + Receiver troyReceiver = new Receiver() { + public void receive(String s) throws Exception { + troyToHaloCtr++; + xenaSender.send("halo to xena because of troy"); + if (troyToHaloCtr >= counter) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + }; + buildReceiver(haloConnection, hectorToHalo, true, hectorReceiver); + buildReceiver(haloConnection, xenaToHalo, true, xenaReceiver); + buildReceiver(haloConnection, troyToHalo, true, troyReceiver); + + haloConnection.start(); + + troyConnection.start(); + troyThread.start(); + + xenaConnection.start(); + xenaThread.start(); + + hectorConnection.start(); + hectorThread.start(); + waitForMessagesToBeDelivered(); + // number of messages received should match messages sent + assertEquals(hectorToHaloCtr, counter); + LOG.info("hectorToHalo received " + hectorToHaloCtr + " messages"); + assertEquals(xenaToHaloCtr, counter); + LOG.info("xenaToHalo received " + xenaToHaloCtr + " messages"); + assertEquals(troyToHaloCtr, counter); + LOG.info("troyToHalo received " + troyToHaloCtr + " messages"); + assertEquals(haloToHectorCtr, counter); + LOG.info("haloToHector received " + haloToHectorCtr + " messages"); + assertEquals(haloToXenaCtr, counter); + LOG.info("haloToXena received " + haloToXenaCtr + " messages"); + assertEquals(haloToTroyCtr, counter); + LOG.info("haloToTroy received " + haloToTroyCtr + " messages"); + + } + + protected void waitForMessagesToBeDelivered() { + // let's give the listeners enough time to read all messages + long maxWaitTime = counter * 3000; + long waitTime = maxWaitTime; + long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); + + synchronized (lock) { + boolean hasMessages = true; + while (hasMessages && waitTime >= 0) { + try { + lock.wait(200); + } catch (InterruptedException e) { + LOG.error(e.toString()); + } + // check if all messages have been received + hasMessages = hectorToHaloCtr < counter || xenaToHaloCtr < counter || troyToHaloCtr < counter || haloToHectorCtr < counter || haloToXenaCtr < counter + || haloToTroyCtr < counter; + waitTime = maxWaitTime - (System.currentTimeMillis() - start); + } + } + } + + public MessageSender buildTransactionalProducer(String queueName, Connection connection) throws Exception { + return new MessageSender(queueName, connection, true, false); + } + + public Thread buildProducer(Connection connection, final String queueName) throws Exception { + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageSender producer = new MessageSender(queueName, connection, false, false); + Thread thread = new Thread() { + + public synchronized void run() { + for (int i = 0; i < counter; i++) { + try { + producer.send(queueName); + if (session.getTransacted()) { + session.commit(); + } + + } catch (Exception e) { + throw new RuntimeException("on " + queueName + " send", e); + } + } + } + }; + return thread; + } + + public void buildReceiver(Connection connection, final String queueName, boolean transacted, final Receiver receiver) throws Exception { + final Session session = transacted ? connection.createSession(true, Session.SESSION_TRANSACTED) : connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer inputMessageConsumer = session.createConsumer(session.createQueue(queueName)); + MessageListener messageListener = new MessageListener() { + + 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(); + } + } + }; + inputMessageConsumer.setMessageListener(messageListener); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TrapMessageInJDBCStoreTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TrapMessageInJDBCStoreTest.java new file mode 100644 index 0000000000..688d066d2a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/TrapMessageInJDBCStoreTest.java @@ -0,0 +1,291 @@ +/** + * 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.bugs; + +import java.io.IOException; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.jdbc.DataSourceServiceSupport; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.jdbc.LeaseDatabaseLocker; +import org.apache.activemq.store.jdbc.TransactionContext; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.LeaseLockerIOExceptionHandler; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test to demostrate a message trapped in the JDBC store and not + * delivered to consumer + * + * The test throws issues the commit to the DB but throws + * an exception back to the broker. This scenario could happen when a network + * cable is disconnected - message is committed to DB but broker does not know. + * + * + */ + +public class TrapMessageInJDBCStoreTest extends TestCase { + + private static final String MY_TEST_Q = "MY_TEST_Q"; + private static final Logger LOG = LoggerFactory + .getLogger(TrapMessageInJDBCStoreTest.class); + private String transportUrl = "tcp://127.0.0.1:0"; + private BrokerService broker; + private TestTransactionContext testTransactionContext; + private TestJDBCPersistenceAdapter jdbc; + + protected BrokerService createBroker(boolean withJMX) throws Exception { + BrokerService broker = new BrokerService(); + + broker.setUseJmx(withJMX); + + EmbeddedDataSource embeddedDataSource = (EmbeddedDataSource) DataSourceServiceSupport.createDataSource(IOHelper.getDefaultDataDirectory()); + embeddedDataSource.setCreateDatabase("create"); + + //wire in a TestTransactionContext (wrapper to TransactionContext) that has an executeBatch() + // method that can be configured to throw a SQL exception on demand + jdbc = new TestJDBCPersistenceAdapter(); + jdbc.setDataSource(embeddedDataSource); + jdbc.setCleanupPeriod(0); + testTransactionContext = new TestTransactionContext(jdbc); + + jdbc.setLockKeepAlivePeriod(1000l); + LeaseDatabaseLocker leaseDatabaseLocker = new LeaseDatabaseLocker(); + leaseDatabaseLocker.setLockAcquireSleepInterval(2000l); + jdbc.setLocker(leaseDatabaseLocker); + + broker.setPersistenceAdapter(jdbc); + + broker.setIoExceptionHandler(new LeaseLockerIOExceptionHandler()); + + transportUrl = broker.addConnector(transportUrl).getPublishableConnectString(); + return broker; + } + + /** + * + * sends 3 messages to the queue. When the second message is being committed to the JDBCStore, $ + * it throws a dummy SQL exception - the message has been committed to the embedded DB before the exception + * is thrown + * + * Excepted correct outcome: receive 3 messages and the DB should contain no messages + * + * @throws Exception + */ + + public void testDBCommitException() throws Exception { + + broker = this.createBroker(false); + broker.deleteAllMessages(); + broker.start(); + broker.waitUntilStarted(); + + LOG.info("***Broker started..."); + + // failover but timeout in 5 seconds so the test does not hang + String failoverTransportURL = "failover:(" + transportUrl + + ")?timeout=5000"; + + + sendMessage(MY_TEST_Q, failoverTransportURL); + + //check db contents + ArrayList dbSeq = dbMessageCount(); + LOG.info("*** after send: db contains message seq " +dbSeq ); + + List consumedMessages = consumeMessages(MY_TEST_Q,failoverTransportURL); + + assertEquals("number of consumed messages",3,consumedMessages.size()); + + //check db contents + dbSeq = dbMessageCount(); + LOG.info("*** after consume - db contains message seq " + dbSeq); + + assertEquals("number of messages in DB after test",0,dbSeq.size()); + + broker.stop(); + broker.waitUntilStopped(); + } + + + + public List consumeMessages(String queue, + String transportURL) throws JMSException { + Connection connection = null; + LOG.debug("*** consumeMessages() called ..."); + + try { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + transportURL); + + connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(queue); + + ArrayList consumedMessages = new ArrayList(); + + MessageConsumer messageConsumer = session.createConsumer(destination); + + while(true){ + TextMessage textMessage= (TextMessage) messageConsumer.receive(4000); + LOG.debug("*** consumed Messages :"+textMessage); + + if(textMessage==null){ + return consumedMessages; + } + consumedMessages.add(textMessage); + } + + + } finally { + if (connection != null) { + connection.close(); + } + } + } + + public void sendMessage(String queue, String transportURL) + throws Exception { + Connection connection = null; + + try { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + transportURL); + + connection = factory.createConnection(); + Session session = connection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(queue); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + TextMessage m = session.createTextMessage("1"); + + LOG.debug("*** send message 1 to broker..."); + producer.send(m); + + // trigger SQL exception in transactionContext + LOG.debug("*** send message 2 to broker"); + m.setText("2"); + producer.send(m); + + //check db contents + ArrayList dbSeq = dbMessageCount(); + LOG.info("*** after send 2 - db contains message seq " + dbSeq); + assertEquals("number of messages in DB after send 2",2,dbSeq.size()); + + LOG.debug("*** send message 3 to broker"); + m.setText("3"); + producer.send(m); + LOG.debug("*** Finished sending messages to broker"); + + } finally { + if (connection != null) { + connection.close(); + } + } + } + + /** + * query the DB to see what messages are left in the store + * @return + * @throws SQLException + * @throws IOException + */ + private ArrayList dbMessageCount() throws SQLException, IOException { + java.sql.Connection conn = ((JDBCPersistenceAdapter) broker.getPersistenceAdapter()).getDataSource().getConnection(); + PreparedStatement statement = conn.prepareStatement("SELECT MSGID_SEQ FROM ACTIVEMQ_MSGS"); + + try{ + + ResultSet result = statement.executeQuery(); + ArrayList dbSeq = new ArrayList(); + + while (result.next()){ + dbSeq.add(result.getLong(1)); + } + + return dbSeq; + + }finally{ + statement.close(); + conn.close(); + + } + + } + + /* + * Mock classes used for testing + */ + + public class TestJDBCPersistenceAdapter extends JDBCPersistenceAdapter { + public TransactionContext getTransactionContext() throws IOException { + return testTransactionContext; + } + } + + public class TestTransactionContext extends TransactionContext { + + private int count; + + public TestTransactionContext( + JDBCPersistenceAdapter jdbcPersistenceAdapter) + throws IOException { + super(jdbcPersistenceAdapter); + } + + public void executeBatch() throws SQLException { + super.executeBatch(); + count++; + LOG.debug("ExecuteBatchOverride: count:" + count, new RuntimeException("executeBatch")); + + // throw on second add message + if (count == 16){ + throw new SQLException("TEST SQL EXCEPTION from executeBatch after super.execution: count:" + count); + } + } + + + + + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/VMTransportClosureTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/VMTransportClosureTest.java new file mode 100644 index 0000000000..6a96a147a5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/VMTransportClosureTest.java @@ -0,0 +1,131 @@ +/** + * 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.bugs; + +import java.io.IOException; + +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ShutdownInfo; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class VMTransportClosureTest extends EmbeddedBrokerTestSupport { + private static final Log LOG = LogFactory + .getLog(VMTransportClosureTest.class); + private static final long MAX_TEST_TIME_MILLIS = 300000; // 5min + private static final int NUM_ATTEMPTS = 100000; + + public void setUp() throws Exception { + setAutoFail(true); + setMaxTestTime(MAX_TEST_TIME_MILLIS); + super.setUp(); + } + + /** + * EmbeddedBrokerTestSupport.createBroker() binds the broker to a VM + * transport address, which results in a call to + * VMTransportFactory.doBind(location): + *

+ * + * public TransportServer doBind(URI location) throws IOException { + * return bind(location, false); + *} + * + *

+ * As a result, VMTransportServer.disposeOnDisconnect is false. + * To expose the bug, we need to have VMTransportServer.disposeOnDisconnect + * true, which is the case when the VMTransportServer is not + * already bound when the first connection is made. + */ + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(isPersistent()); + // answer.addConnector(bindAddress); + return answer; + } + + /** + * This test demonstrates how the "disposeOnDisonnect" feature of + * VMTransportServer can incorrectly close all VM connections to the local + * broker. + */ + public void testPrematureClosure() throws Exception { + + // Open a persistent connection to the local broker. The persistent + // connection is maintained through the test and should prevent the + // VMTransportServer from stopping itself when the local transport is + // closed. + ActiveMQConnection persistentConn = (ActiveMQConnection) createConnection(); + persistentConn.start(); + Session session = persistentConn.createSession(true, + Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(destination); + + for (int i = 0; i < NUM_ATTEMPTS; i++) { + LOG.info("Attempt: " + i); + + // Open and close a local transport connection. As is done by by + // most users of the transport, ensure that the transport is stopped + // when closed by the peer (via ShutdownInfo). Closing the local + // transport should not affect the persistent connection. + final Transport localTransport = TransportFactory.connect(broker + .getVmConnectorURI()); + localTransport.setTransportListener(new TransportListener() { + public void onCommand(Object command) { + if (command instanceof ShutdownInfo) { + try { + localTransport.stop(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } + + public void onException(IOException error) { + // ignore + } + + public void transportInterupted() { + // ignore + } + + public void transportResumed() { + // ignore + } + }); + + localTransport.start(); + localTransport.stop(); + + // Ensure that the persistent connection is still usable. + producer.send(session.createMessage()); + session.rollback(); + } + + persistentConn.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/VerifySteadyEnqueueRate.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/VerifySteadyEnqueueRate.java new file mode 100644 index 0000000000..79394531e1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/VerifySteadyEnqueueRate.java @@ -0,0 +1,153 @@ +/** + * 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.bugs; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import java.io.File; +import java.text.DateFormat; +import java.util.Date; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +public class VerifySteadyEnqueueRate extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(VerifySteadyEnqueueRate.class); + + private static int max_messages = 1000000; + private final String destinationName = getName() + "_Queue"; + private BrokerService broker; + final boolean useTopic = false; + + protected static final String payload = new String(new byte[24]); + + @Override + public void setUp() throws Exception { + startBroker(); + } + + @Override + public void tearDown() throws Exception { + broker.stop(); + } + + @SuppressWarnings("unused") + public void testEnqueueRateCanMeetSLA() throws Exception { + if (true) { + return; + } + doTestEnqueue(false); + } + + private void doTestEnqueue(final boolean transacted) throws Exception { + final long min = 100; + final AtomicLong total = new AtomicLong(0); + final AtomicLong slaViolations = new AtomicLong(0); + final AtomicLong max = new AtomicLong(0); + final int numThreads = 6; + + Runnable runner = new Runnable() { + + @Override + public void run() { + try { + MessageSender producer = new MessageSender(destinationName, + createConnection(), transacted, useTopic); + + for (int i = 0; i < max_messages; i++) { + long startT = System.currentTimeMillis(); + producer.send(payload); + long endT = System.currentTimeMillis(); + long duration = endT - startT; + + total.incrementAndGet(); + + if (duration > max.get()) { + max.set(duration); + } + + if (duration > min) { + slaViolations.incrementAndGet(); + System.err.println("SLA violation @ "+Thread.currentThread().getName() + + " " + + DateFormat.getTimeInstance().format( + new Date(startT)) + " at message " + + i + " send time=" + duration + + " - Total SLA violations: "+slaViolations.get()+"/"+total.get()+" ("+String.format("%.6f", 100.0*slaViolations.get()/total.get())+"%)"); + } + } + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + System.out.println("Max Violation = " + max + " - Total SLA violations: "+slaViolations.get()+"/"+total.get()+" ("+String.format("%.6f", 100.0*slaViolations.get()/total.get())+"%)"); + } + }; + ExecutorService executor = Executors.newCachedThreadPool(); + + for (int i = 0; i < numThreads; i++) { + executor.execute(runner); + } + + executor.shutdown(); + while(!executor.isTerminated()) { + executor.awaitTermination(10, TimeUnit.SECONDS); + } + } + + private Connection createConnection() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getConnectUri()); + return factory.createConnection(); + } + + private void startBroker() throws Exception { + broker = new BrokerService(); + //broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(true); + broker.setUseJmx(true); + + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(new File("target/activemq-data/kahadb")); + // The setEnableJournalDiskSyncs(false) setting is a little dangerous right now, as I have not verified + // what happens if the index is updated but a journal update is lost. + // Index is going to be in consistent, but can it be repaired? + kaha.setEnableJournalDiskSyncs(false); + // Using a bigger journal file size makes he take fewer spikes as it is not switching files as often. + kaha.setJournalMaxFileLength(1024*1024*100); + + // small batch means more frequent and smaller writes + kaha.setIndexWriteBatchSize(100); + // do the index write in a separate thread + kaha.setEnableIndexWriteAsync(true); + + broker.setPersistenceAdapter(kaha); + + broker.addConnector("tcp://localhost:0").setName("Default"); + broker.start(); + LOG.info("Starting broker.."); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/ActiveMQTestCase.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/ActiveMQTestCase.java new file mode 100644 index 0000000000..01ecdb1a64 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/ActiveMQTestCase.java @@ -0,0 +1,166 @@ +/* ==================================================================== + 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.bugs.amq1095; + +import java.net.URI; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; + +/** + *

+ * Common functionality for ActiveMQ test cases. + *

+ * + * @author Rainer Klute <rainer.klute@dp-itsolutions.de> + * @since 2007-08-10 + * @version $Id: ActiveMQTestCase.java 12 2007-08-14 12:02:02Z rke $ + */ +public class ActiveMQTestCase extends TestCase +{ + private Context context; + private BrokerService broker; + protected Connection connection; + protected Destination destination; + private final List consumersToEmpty = new LinkedList(); + protected final long RECEIVE_TIMEOUT = 500; + + + /**

Constructor

*/ + public ActiveMQTestCase() + {} + + /**

Constructor

+ * @param name the test case's name + */ + public ActiveMQTestCase(final String name) + { + super(name); + } + + /** + *

Sets up the JUnit testing environment. + */ + @Override + protected void setUp() + { + URI uri; + try + { + /* Copy all system properties starting with "java.naming." to the initial context. */ + final Properties systemProperties = System.getProperties(); + final Properties jndiProperties = new Properties(); + for (final Iterator i = systemProperties.keySet().iterator(); i.hasNext();) + { + final String key = (String) i.next(); + if (key.startsWith("java.naming.") || key.startsWith("topic.") || + key.startsWith("queue.")) + { + final String value = (String) systemProperties.get(key); + jndiProperties.put(key, value); + } + } + context = new InitialContext(jndiProperties); + uri = new URI("xbean:org/apache/activemq/bugs/amq1095/activemq.xml"); + broker = BrokerFactory.createBroker(uri); + broker.start(); + } + catch (Exception ex) + { + throw new RuntimeException(ex); + } + + final ConnectionFactory connectionFactory; + try + { + /* Lookup the connection factory. */ + connectionFactory = (ConnectionFactory) context.lookup("TopicConnectionFactory"); + + destination = new ActiveMQTopic("TestTopic"); + + /* Create a connection: */ + connection = connectionFactory.createConnection(); + connection.setClientID("sampleClientID"); + } + catch (JMSException ex1) + { + ex1.printStackTrace(); + fail(ex1.toString()); + } + catch (NamingException ex2) { + ex2.printStackTrace(); + fail(ex2.toString()); + } + catch (Throwable ex3) { + ex3.printStackTrace(); + fail(ex3.toString()); + } + } + + + /** + *

+ * Tear down the testing environment by receiving any messages that might be + * left in the topic after a failure and shutting down the broker properly. + * This is quite important for subsequent test cases that assume the topic + * to be empty. + *

+ */ + @Override + protected void tearDown() throws Exception { + TextMessage msg; + try { + for (final Iterator i = consumersToEmpty.iterator(); i.hasNext();) + { + final MessageConsumer consumer = i.next(); + if (consumer != null) + do + msg = (TextMessage) consumer.receive(RECEIVE_TIMEOUT); + while (msg != null); + } + } catch (Exception e) { + } + if (connection != null) { + connection.stop(); + } + broker.stop(); + } + + protected void registerToBeEmptiedOnShutdown(final MessageConsumer consumer) + { + consumersToEmpty.add(consumer); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/MessageSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/MessageSelectorTest.java new file mode 100644 index 0000000000..e9aa3cab02 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/MessageSelectorTest.java @@ -0,0 +1,227 @@ +/* ==================================================================== + 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.bugs.amq1095; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +/** + *

+ * Test cases for various ActiveMQ functionalities. + *

+ * + *
    + *
  • + *

    + * Durable subscriptions are used. + *

    + *
  • + *
  • + *

    + * The Kaha persistence manager is used. + *

    + *
  • + *
  • + *

    + * An already existing Kaha directory is used. Everything runs fine if the + * ActiveMQ broker creates a new Kaha directory. + *

    + *
  • + *
+ * + * @author Rainer Klute <rainer.klute@dp-itsolutions.de> + * @since 2007-08-09 + * @version $Id: MessageSelectorTest.java 12 2007-08-14 12:02:02Z rke $ + */ +public class MessageSelectorTest extends ActiveMQTestCase { + + private MessageConsumer consumer1; + private MessageConsumer consumer2; + + /**

Constructor

*/ + public MessageSelectorTest() + {} + + /**

Constructor

+ * @param name the test case's name + */ + public MessageSelectorTest(final String name) + { + super(name); + } + + /** + *

+ * Tests whether message selectors work for durable subscribers. + *

+ */ + public void testMessageSelectorForDurableSubscribersRunA() + { + runMessageSelectorTest(true); + } + + /** + *

+ * Tests whether message selectors work for durable subscribers. + *

+ */ + public void testMessageSelectorForDurableSubscribersRunB() + { + runMessageSelectorTest(true); + } + + /** + *

+ * Tests whether message selectors work for non-durable subscribers. + *

+ */ + public void testMessageSelectorForNonDurableSubscribers() + { + runMessageSelectorTest(false); + } + + /** + *

+ * Tests whether message selectors work. This is done by sending two + * messages to a topic. Both have an int property with different values. Two + * subscribers use message selectors to receive the messages. Each one + * should receive exactly one of the messages. + *

+ */ + private void runMessageSelectorTest(final boolean isDurableSubscriber) + { + try + { + final String PROPERTY_CONSUMER = "consumer"; + final String CONSUMER_1 = "Consumer 1"; + final String CONSUMER_2 = "Consumer 2"; + final String MESSAGE_1 = "Message to " + CONSUMER_1; + final String MESSAGE_2 = "Message to " + CONSUMER_2; + + assertNotNull(connection); + assertNotNull(destination); + + final Session producingSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = producingSession.createProducer(destination); + + final Session consumingSession1 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session consumingSession2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + if (isDurableSubscriber) + { + consumer1 = consumingSession1.createDurableSubscriber + ((Topic) destination, CONSUMER_1, PROPERTY_CONSUMER + " = 1", false); + consumer2 = consumingSession2.createDurableSubscriber + ((Topic) destination, CONSUMER_2, PROPERTY_CONSUMER + " = 2", false); + } + else + { + consumer1 = consumingSession1.createConsumer(destination, PROPERTY_CONSUMER + " = 1"); + consumer2 = consumingSession2.createConsumer(destination, PROPERTY_CONSUMER + " = 2"); + } + registerToBeEmptiedOnShutdown(consumer1); + registerToBeEmptiedOnShutdown(consumer2); + + connection.start(); + + TextMessage msg1; + TextMessage msg2; + int propertyValue; + String contents; + + /* Try to receive any messages from the consumers. There shouldn't be any yet. */ + msg1 = (TextMessage) consumer1.receive(RECEIVE_TIMEOUT); + if (msg1 != null) + { + final StringBuffer msg = new StringBuffer("The consumer read a message that was left over from a former ActiveMQ broker run."); + propertyValue = msg1.getIntProperty(PROPERTY_CONSUMER); + contents = msg1.getText(); + if (propertyValue != 1) // Is the property value as expected? + { + msg.append(" That message does not match the consumer's message selector."); + fail(msg.toString()); + } + assertEquals(1, propertyValue); + assertEquals(MESSAGE_1, contents); + } + msg2 = (TextMessage) consumer2.receive(RECEIVE_TIMEOUT); + if (msg2 != null) + { + final StringBuffer msg = new StringBuffer("The consumer read a message that was left over from a former ActiveMQ broker run."); + propertyValue = msg2.getIntProperty(PROPERTY_CONSUMER); + contents = msg2.getText(); + if (propertyValue != 2) // Is the property value as expected? + { + msg.append(" That message does not match the consumer's message selector."); + fail(msg.toString()); + } + assertEquals(2, propertyValue); + assertEquals(MESSAGE_2, contents); + } + + /* Send two messages. Each is targeted at one of the consumers. */ + TextMessage msg; + msg = producingSession.createTextMessage(); + msg.setText(MESSAGE_1); + msg.setIntProperty(PROPERTY_CONSUMER, 1); + producer.send(msg); + + msg = producingSession.createTextMessage(); + msg.setText(MESSAGE_2); + msg.setIntProperty(PROPERTY_CONSUMER, 2); + producer.send(msg); + + /* Receive the messages that have just been sent. */ + + /* Use consumer 1 to receive one of the messages. The receive() + * method is called twice to make sure there is nothing else in + * stock for this consumer. */ + msg1 = (TextMessage) consumer1.receive(RECEIVE_TIMEOUT); + assertNotNull(msg1); + propertyValue = msg1.getIntProperty(PROPERTY_CONSUMER); + contents = msg1.getText(); + assertEquals(1, propertyValue); + assertEquals(MESSAGE_1, contents); + msg1 = (TextMessage) consumer1.receive(RECEIVE_TIMEOUT); + assertNull(msg1); + + /* Use consumer 2 to receive the other message. The receive() + * method is called twice to make sure there is nothing else in + * stock for this consumer. */ + msg2 = (TextMessage) consumer2.receive(RECEIVE_TIMEOUT); + assertNotNull(msg2); + propertyValue = msg2.getIntProperty(PROPERTY_CONSUMER); + contents = msg2.getText(); + assertEquals(2, propertyValue); + assertEquals(MESSAGE_2, contents); + msg2 = (TextMessage) consumer2.receive(RECEIVE_TIMEOUT); + assertNull(msg2); + } + catch (JMSException ex) + { + ex.printStackTrace(); + fail(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/activemq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/activemq.xml new file mode 100644 index 0000000000..c89e261010 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1095/activemq.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1974/TryJmsClient.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1974/TryJmsClient.java new file mode 100644 index 0000000000..c8b4503c4d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1974/TryJmsClient.java @@ -0,0 +1,150 @@ +/** + * 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.bugs.amq1974; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.transport.discovery.simple.SimpleDiscoveryAgent; + +import javax.jms.*; +import java.io.File; +import java.net.URISyntaxException; + +public class TryJmsClient +{ + private final BrokerService broker = new BrokerService(); + + public static void main(String[] args) throws Exception { + new TryJmsClient().start(); + } + + private void start() throws Exception { + + broker.setUseJmx(false); + broker.setPersistent(true); + broker.setBrokerName("TestBroker"); + broker.getSystemUsage().setSendFailIfNoSpace(true); + + broker.getSystemUsage().getMemoryUsage().setLimit(10 * 1024 * 1024); + + LevelDBStore persist = new LevelDBStore(); + persist.setDirectory(new File("/tmp/broker2")); + persist.setLogSize(20 * 1024 * 1024); + broker.setPersistenceAdapter(persist); + + String brokerUrl = "tcp://localhost:4501"; + broker.addConnector(brokerUrl); + + broker.start(); + + addNetworkBroker(); + + startUsageMonitor(broker); + + startMessageSend(); + + synchronized(this) { + this.wait(); + } + } + + private void startUsageMonitor(final BrokerService brokerService) { + new Thread(new Runnable() { + public void run() { + while (true) { + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("ActiveMQ memeory " + brokerService.getSystemUsage().getMemoryUsage().getPercentUsage() + + " " + brokerService.getSystemUsage().getMemoryUsage().getUsage()); + System.out.println("ActiveMQ message store " + brokerService.getSystemUsage().getStoreUsage().getPercentUsage()); + System.out.println("ActiveMQ temp space " + brokerService.getSystemUsage().getTempUsage().getPercentUsage()); + } + } + }).start(); + } + + private void addNetworkBroker() throws Exception { + + DiscoveryNetworkConnector dnc = new DiscoveryNetworkConnector(); + dnc.setNetworkTTL(1); + dnc.setBrokerName("TestBroker"); + dnc.setName("Broker1Connector"); + dnc.setDynamicOnly(true); + + SimpleDiscoveryAgent discoveryAgent = new SimpleDiscoveryAgent(); + String remoteUrl = "tcp://localhost:4500"; + discoveryAgent.setServices(remoteUrl); + + dnc.setDiscoveryAgent(discoveryAgent); + + broker.addNetworkConnector(dnc); + dnc.start(); + } + + private void startMessageSend() { + new Thread(new MessageSend()).start(); + } + + private class MessageSend implements Runnable { + public void run() { + try { + String url = "vm://TestBroker"; + ActiveMQConnection connection = ActiveMQConnection.makeConnection(url); + connection.setDispatchAsync(true); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = session.createTopic("TestDestination"); + + MessageProducer producer = session.createProducer(dest); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + for(int i = 0; i < 99999999; i++) { + TextMessage message = session.createTextMessage("test" + i); + + /* + try { + Thread.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + */ + + try { + producer.send(message); + } catch (Exception e ) { + e.printStackTrace(); + System.out.println("TOTAL number of messages sent " + i); + break; + } + + if (i % 1000 == 0) { + System.out.println("sent message " + message.getJMSMessageID()); + } + } + } catch (JMSException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1974/TryJmsManager.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1974/TryJmsManager.java new file mode 100644 index 0000000000..3f5898719d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq1974/TryJmsManager.java @@ -0,0 +1,124 @@ +/** + * 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.bugs.amq1974; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.transport.discovery.simple.SimpleDiscoveryAgent; + +import javax.jms.*; +import java.io.File; +import java.net.URISyntaxException; + +public class TryJmsManager { + + private final BrokerService broker = new BrokerService(); + + public static void main(String[] args) throws Exception { + new TryJmsManager().start(); + } + + private void start() throws Exception { + + broker.setUseJmx(false); + broker.setPersistent(true); + broker.setBrokerName("TestBroker"); + broker.getSystemUsage().setSendFailIfNoSpace(true); + + broker.getSystemUsage().getMemoryUsage().setLimit(10 * 1024 * 1024); + + LevelDBStore persist = new LevelDBStore(); + persist.setDirectory(new File("/tmp/broker1")); + persist.setLogSize(20 * 1024 * 1024); + broker.setPersistenceAdapter(persist); + + String brokerUrl = "tcp://localhost:4500"; + broker.addConnector(brokerUrl); + + broker.start(); + + addNetworkBroker(); + + startUsageMonitor(broker); + + startMessageConsumer(); + + synchronized(this) { + this.wait(); + } + } + + private void startUsageMonitor(final BrokerService brokerService) { + new Thread(new Runnable() { + public void run() { + while (true) { + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("ActiveMQ memeory " + brokerService.getSystemUsage().getMemoryUsage().getPercentUsage() + + " " + brokerService.getSystemUsage().getMemoryUsage().getUsage()); + System.out.println("ActiveMQ message store " + brokerService.getSystemUsage().getStoreUsage().getPercentUsage()); + System.out.println("ActiveMQ temp space " + brokerService.getSystemUsage().getTempUsage().getPercentUsage()); + } + } + }).start(); + } + + private void addNetworkBroker() throws Exception { + DiscoveryNetworkConnector dnc = new DiscoveryNetworkConnector(); + dnc.setNetworkTTL(1); + dnc.setBrokerName("TestBroker"); + dnc.setName("Broker1Connector"); + dnc.setDynamicOnly(true); + + SimpleDiscoveryAgent discoveryAgent = new SimpleDiscoveryAgent(); + String remoteUrl = "tcp://localhost:4501"; + discoveryAgent.setServices(remoteUrl); + + dnc.setDiscoveryAgent(discoveryAgent); + + broker.addNetworkConnector(dnc); + dnc.start(); + } + + private void startMessageConsumer() throws JMSException, URISyntaxException { + String url = "vm://TestBroker"; + ActiveMQConnection connection = ActiveMQConnection.makeConnection(url); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = session.createTopic("TestDestination"); + + MessageConsumer consumer = session.createConsumer(dest); + consumer.setMessageListener(new MessageListener() { + + public void onMessage(Message message) { + try { + System.out.println("got message " + message.getJMSMessageID()); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + ); + + connection.start(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/JaasStompSSLBroker1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/JaasStompSSLBroker1.xml new file mode 100644 index 0000000000..9b82ae1ed5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/JaasStompSSLBroker1.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/JaasStompSSLBroker2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/JaasStompSSLBroker2.xml new file mode 100644 index 0000000000..0b68aed7d2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/JaasStompSSLBroker2.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/groups2.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/groups2.properties new file mode 100644 index 0000000000..ad1398f26a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/groups2.properties @@ -0,0 +1,20 @@ +/** + * 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. + */ +admins=system,dave +tempDestinationAdmins=system,user,dave +users=system,tester,user,dave,admin +guests=guest diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/login.config b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/login.config new file mode 100644 index 0000000000..898a174983 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/login.config @@ -0,0 +1,22 @@ +/** + * 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. + */ +CertLogin { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="users2.properties + org.apache.activemq.jaas.textfiledn.group="groups2.properties"; +}; diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/users2.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/users2.properties new file mode 100644 index 0000000000..6c19d195e1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/conf/users2.properties @@ -0,0 +1,23 @@ +/** + * 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. + */ +guests=myguests +system=manager +admin=apassword +user=password +guest=password +tester=mypassword +dave=CN=Hello Dave Stanley, OU=FuseSource, O=Progress, L=Unknown, ST=MA, C=US diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/keys/broker2.ks b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/keys/broker2.ks new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/keys/client2.ks b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/keys/client2.ks new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/keys/client2.ts b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq3625/keys/client2.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/InconsistentConnectorPropertiesBehaviour.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/InconsistentConnectorPropertiesBehaviour.xml new file mode 100644 index 0000000000..325e354d6b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/InconsistentConnectorPropertiesBehaviour.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/JaasStompSSLBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/JaasStompSSLBroker.xml new file mode 100644 index 0000000000..a24502864d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/JaasStompSSLBroker.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/dns.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/dns.properties new file mode 100644 index 0000000000..fcfe558710 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/dns.properties @@ -0,0 +1,17 @@ +/** + * 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. + */ +client=CN=client, OU=activemq, O=apache diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/groups.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/groups.properties new file mode 100644 index 0000000000..4171c5ffe4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/groups.properties @@ -0,0 +1,18 @@ +/** + * 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. + */ +admins=system,client +guests=guest diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/login.config b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/login.config new file mode 100644 index 0000000000..c3d87c1769 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/login.config @@ -0,0 +1,30 @@ +/** + * 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. + */ +activemq-domain { + + org.apache.activemq.jaas.PropertiesLoginModule requisite + debug=true + org.apache.activemq.jaas.properties.user="users.properties" + org.apache.activemq.jaas.properties.group="groups.properties"; +}; + +activemq-ssl-domain { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="dns.properties" + org.apache.activemq.jaas.textfiledn.group="groups.properties"; +}; diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/users.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/users.properties new file mode 100644 index 0000000000..2915bdb06a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq4126/users.properties @@ -0,0 +1,18 @@ +/** + * 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. + */ +system=manager +guest=password \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq5035/activemq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq5035/activemq.xml new file mode 100644 index 0000000000..660fff5195 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/amq5035/activemq.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/embedded/EmbeddedActiveMQ.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/embedded/EmbeddedActiveMQ.java new file mode 100644 index 0000000000..3b4f2fd50f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/embedded/EmbeddedActiveMQ.java @@ -0,0 +1,114 @@ +/** + * 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.bugs.embedded; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.log4j.Logger; + +public class EmbeddedActiveMQ +{ + + private static Logger logger = Logger.getLogger(EmbeddedActiveMQ.class); + + public static void main(String[] args) + { + + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + BrokerService brokerService = null; + Connection connection = null; + + logger.info("Start..."); + try + { + brokerService = new BrokerService(); + brokerService.setBrokerName("TestMQ"); + brokerService.setUseJmx(true); + logger.info("Broker '" + brokerService.getBrokerName() + "' is starting........"); + brokerService.start(); + ConnectionFactory fac = new ActiveMQConnectionFactory("vm://TestMQ"); + connection = fac.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination queue = session.createQueue("TEST.QUEUE"); + MessageProducer producer = session.createProducer(queue); + for (int i = 0; i < 1000;i++) { + Message msg = session.createTextMessage("test"+i); + producer.send(msg); + } + logger.info(ThreadExplorer.show("Active threads after start:")); + System.out.println("Press return to stop........"); + String key = br.readLine(); + } + + catch (Exception e) + { + e.printStackTrace(); + } + finally + { + try + { + br.close(); + logger.info("Broker '" + brokerService.getBrokerName() + "' is stopping........"); + connection.close(); + brokerService.stop(); + sleep(8); + logger.info(ThreadExplorer.show("Active threads after stop:")); + + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + logger.info("Waiting for list theads is greater then 1 ..."); + int numTh = ThreadExplorer.active(); + + while (numTh > 2) + { + sleep(3); + numTh = ThreadExplorer.active(); + logger.info(ThreadExplorer.show("Still active threads:")); + } + + System.out.println("Stop..."); + } + + private static void sleep(int second) + { + try + { + logger.info("Waiting for " + second + "s..."); + Thread.sleep(second * 1000L); + } + catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/embedded/ThreadExplorer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/embedded/ThreadExplorer.java new file mode 100644 index 0000000000..eab5fd148f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/bugs/embedded/ThreadExplorer.java @@ -0,0 +1,168 @@ +/** + * 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.bugs.embedded; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.log4j.Logger; + +public class ThreadExplorer +{ + static Logger logger = Logger.getLogger(ThreadExplorer.class); + + public static Thread[] listThreads() + { + + int nThreads = Thread.activeCount(); + Thread ret[] = new Thread[nThreads]; + + Thread.enumerate(ret); + + return ret; + + } + + /** + * Helper function to access a thread per name (ignoring case) + * + * @param name + * @return + */ + public static Thread fetchThread(String name) + { + Thread[] threadArray = listThreads(); + // for (Thread t : threadArray) + for (int i = 0; i < threadArray.length; i++) + { + Thread t = threadArray[i]; + if (t.getName().equalsIgnoreCase(name)) + return t; + } + return null; + } + + /** + * Allow for killing threads + * + * @param threadName + * @param isStarredExp + * (regular expressions with *) + */ + @SuppressWarnings("deprecation") + public static int kill(String threadName, boolean isStarredExp, String motivation) + { + String me = "ThreadExplorer.kill: "; + if (logger.isDebugEnabled()) + { + logger.debug("Entering " + me + " with " + threadName + " isStarred: " + isStarredExp); + } + int ret = 0; + Pattern mypattern = null; + if (isStarredExp) + { + String realreg = threadName.toLowerCase().replaceAll("\\*", "\\.\\*"); + mypattern = Pattern.compile(realreg); + + } + Thread[] threads = listThreads(); + for (int i = 0; i < threads.length; i++) + { + Thread thread = threads[i]; + if (thread == null) + continue; + // kill the thread unless it is not current thread + boolean matches = false; + + if (isStarredExp) + { + Matcher matcher = mypattern.matcher(thread.getName().toLowerCase()); + matches = matcher.matches(); + } + else + { + matches = (thread.getName().equalsIgnoreCase(threadName)); + } + if (matches && (Thread.currentThread() != thread) && !thread.getName().equals("main")) + { + if (logger.isInfoEnabled()) + logger.info("Killing thread named [" + thread.getName() + "]"); // , removing its uncaught + // exception handler to + // avoid ThreadDeath + // exception tracing + // "+motivation ); + + ret++; + + // PK leaving uncaught exception handler otherwise master push + // cannot recover from this error + // thread.setUncaughtExceptionHandler(null); + try + { + thread.stop(); + } + catch (ThreadDeath e) + { + logger.warn("Thread already death.", e); + } + + } + } + return ret; + } + + public static String show(String title) + { + StringBuffer out = new StringBuffer(); + Thread[] threadArray = ThreadExplorer.listThreads(); + + out.append(title + "\n"); + for (int i = 0; i < threadArray.length; i++) + { + Thread thread = threadArray[i]; + + if (thread != null) + { + out.append("* [" + thread.getName() + "] " + (thread.isDaemon() ? "(Daemon)" : "") + + " Group: " + thread.getThreadGroup().getName() + "\n"); + } + else + { + out.append("* ThreadDeath: " + thread + "\n"); + } + + } + return out.toString(); + } + + public static int active() + { + int count = 0; + Thread[] threadArray = ThreadExplorer.listThreads(); + + for (int i = 0; i < threadArray.length; i++) + { + Thread thread = threadArray[i]; + if (thread != null) + { + count++; + } + } + + return count; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQBytesMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQBytesMessageTest.java new file mode 100644 index 0000000000..0219815688 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQBytesMessageTest.java @@ -0,0 +1,488 @@ +/** + * 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.command; + +import javax.jms.JMSException; +import javax.jms.MessageFormatException; +import javax.jms.MessageNotReadableException; +import javax.jms.MessageNotWriteableException; + +import junit.framework.TestCase; + +/** + * + */ +public class ActiveMQBytesMessageTest extends TestCase { + + public ActiveMQBytesMessageTest(String name) { + super(name); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ActiveMQBytesMessageTest.class); + } + + /* + * @see TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + } + + /* + * @see TestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testGetDataStructureType() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + assertEquals(msg.getDataStructureType(), CommandTypes.ACTIVEMQ_BYTES_MESSAGE); + } + + public void testGetBodyLength() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + int len = 10; + try { + for (int i = 0; i < len; i++) { + msg.writeLong(5L); + } + } catch (JMSException ex) { + ex.printStackTrace(); + } + try { + msg.reset(); + assertTrue(msg.getBodyLength() == (len * 8)); + } catch (Throwable e) { + e.printStackTrace(); + assertTrue(false); + } + } + + public void testReadBoolean() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeBoolean(true); + msg.reset(); + assertTrue(msg.readBoolean()); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadByte() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeByte((byte) 2); + msg.reset(); + assertTrue(msg.readByte() == 2); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadUnsignedByte() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeByte((byte) 2); + msg.reset(); + assertTrue(msg.readUnsignedByte() == 2); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadShort() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeShort((short) 3000); + msg.reset(); + assertTrue(msg.readShort() == 3000); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadUnsignedShort() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeShort((short) 3000); + msg.reset(); + assertTrue(msg.readUnsignedShort() == 3000); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadChar() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeChar('a'); + msg.reset(); + assertTrue(msg.readChar() == 'a'); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadInt() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeInt(3000); + msg.reset(); + assertTrue(msg.readInt() == 3000); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadLong() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeLong(3000); + msg.reset(); + assertTrue(msg.readLong() == 3000); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadFloat() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeFloat(3.3f); + msg.reset(); + assertTrue(msg.readFloat() == 3.3f); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadDouble() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeDouble(3.3d); + msg.reset(); + assertTrue(msg.readDouble() == 3.3d); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadUTF() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + String str = "this is a test"; + msg.writeUTF(str); + msg.reset(); + assertTrue(msg.readUTF().equals(str)); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + /* + * Class to test for int readBytes(byte[]) + */ + public void testReadBytesbyteArray() { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + byte[] data = new byte[50]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) i; + } + msg.writeBytes(data); + msg.reset(); + byte[] test = new byte[data.length]; + msg.readBytes(test); + for (int i = 0; i < test.length; i++) { + assertTrue(test[i] == i); + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testWriteObject() throws JMSException { + ActiveMQBytesMessage msg = new ActiveMQBytesMessage(); + try { + msg.writeObject("fred"); + msg.writeObject(Boolean.TRUE); + msg.writeObject(Character.valueOf('q')); + msg.writeObject(Byte.valueOf((byte) 1)); + msg.writeObject(Short.valueOf((short) 3)); + msg.writeObject(Integer.valueOf(3)); + msg.writeObject(Long.valueOf(300L)); + msg.writeObject(new Float(3.3f)); + msg.writeObject(new Double(3.3)); + msg.writeObject(new byte[3]); + } catch (MessageFormatException mfe) { + fail("objectified primitives should be allowed"); + } + try { + msg.writeObject(new Object()); + fail("only objectified primitives are allowed"); + } catch (MessageFormatException mfe) { + } + } + + + /* new */ + public void testClearBody() throws JMSException { + ActiveMQBytesMessage bytesMessage = new ActiveMQBytesMessage(); + try { + bytesMessage.writeInt(1); + bytesMessage.clearBody(); + assertFalse(bytesMessage.isReadOnlyBody()); + bytesMessage.writeInt(1); + bytesMessage.readInt(); + } catch (MessageNotReadableException mnwe) { + } catch (MessageNotWriteableException mnwe) { + assertTrue(false); + } + } + + public void testReset() throws JMSException { + ActiveMQBytesMessage message = new ActiveMQBytesMessage(); + try { + message.writeDouble(24.5); + message.writeLong(311); + } catch (MessageNotWriteableException mnwe) { + fail("should be writeable"); + } + message.reset(); + try { + assertTrue(message.isReadOnlyBody()); + assertEquals(message.readDouble(), 24.5, 0); + assertEquals(message.readLong(), 311); + } catch (MessageNotReadableException mnre) { + fail("should be readable"); + } + try { + message.writeInt(33); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + } + + public void testReadOnlyBody() throws JMSException { + ActiveMQBytesMessage message = new ActiveMQBytesMessage(); + try { + message.writeBoolean(true); + message.writeByte((byte) 1); + message.writeByte((byte) 1); + message.writeBytes(new byte[1]); + message.writeBytes(new byte[3], 0, 2); + message.writeChar('a'); + message.writeDouble(1.5); + message.writeFloat((float) 1.5); + message.writeInt(1); + message.writeLong(1); + message.writeObject("stringobj"); + message.writeShort((short) 1); + message.writeShort((short) 1); + message.writeUTF("utfstring"); + } catch (MessageNotWriteableException mnwe) { + fail("Should be writeable"); + } + message.reset(); + try { + message.readBoolean(); + message.readByte(); + message.readUnsignedByte(); + message.readBytes(new byte[1]); + message.readBytes(new byte[2], 2); + message.readChar(); + message.readDouble(); + message.readFloat(); + message.readInt(); + message.readLong(); + message.readUTF(); + message.readShort(); + message.readUnsignedShort(); + message.readUTF(); + } catch (MessageNotReadableException mnwe) { + fail("Should be readable"); + } + try { + message.writeBoolean(true); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeByte((byte) 1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeBytes(new byte[3], 0, 2); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeChar('a'); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeDouble(1.5); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeFloat((float) 1.5); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeInt(1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeLong(1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeObject("stringobj"); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeShort((short) 1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeUTF("utfstring"); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + } + + public void testWriteOnlyBody() throws JMSException { + ActiveMQBytesMessage message = new ActiveMQBytesMessage(); + message.clearBody(); + try { + message.writeBoolean(true); + message.writeByte((byte) 1); + message.writeByte((byte) 1); + message.writeBytes(new byte[1]); + message.writeBytes(new byte[3], 0, 2); + message.writeChar('a'); + message.writeDouble(1.5); + message.writeFloat((float) 1.5); + message.writeInt(1); + message.writeLong(1); + message.writeObject("stringobj"); + message.writeShort((short) 1); + message.writeShort((short) 1); + message.writeUTF("utfstring"); + } catch (MessageNotWriteableException mnwe) { + fail("Should be writeable"); + } + try { + message.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException mnwe) { + } + try { + message.readByte(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readUnsignedByte(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readBytes(new byte[2], 2); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readChar(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readDouble(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readFloat(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readInt(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readLong(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readUTF(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readShort(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readUnsignedShort(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readUTF(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQDestinationTest.java new file mode 100644 index 0000000000..844be349ad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQDestinationTest.java @@ -0,0 +1,145 @@ +/** + * 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.command; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.TemporaryQueue; +import javax.jms.TemporaryTopic; +import javax.jms.Topic; + +import junit.framework.Test; + +public class ActiveMQDestinationTest extends DataStructureTestSupport { + + public ActiveMQDestination destination; + + public void initCombosForTestDestinationMarshaling() { + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), + new ActiveMQTopic("TEST"), + new ActiveMQTempQueue("TEST:1"), + new ActiveMQTempTopic("TEST:1"), + new ActiveMQTempQueue("TEST"), + new ActiveMQTempTopic("TEST"), + new ActiveMQQueue("TEST?option=value"), + new ActiveMQTopic("TEST?option=value"), + new ActiveMQTempQueue("TEST:1?option=value"), + new ActiveMQTempTopic("TEST:1?option=value")}); + } + + public void testDestinationMarshaling() throws IOException { + assertBeanMarshalls(destination); + } + + public void initCombosForTestDestinationOptions() { + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST?k1=v1&k2=v2"), + new ActiveMQTopic("TEST?k1=v1&k2=v2"), + new ActiveMQTempQueue("TEST:1?k1=v1&k2=v2"), + new ActiveMQTempTopic("TEST:1?k1=v1&k2=v2")}); + } + + public void testDestinationOptions() throws IOException { + Map options = destination.getOptions(); + assertNotNull(options); + assertEquals("v1", options.get("k1")); + assertEquals("v2", options.get("k2")); + } + + public void testSorting() throws Exception { + SortedSet set = new TreeSet(); + ActiveMQDestination[] destinations = {new ActiveMQQueue("A"), new ActiveMQQueue("B"), + new ActiveMQTopic("A"), new ActiveMQTopic("B")}; + List expected = Arrays.asList(destinations); + set.addAll(expected); + List actual = new ArrayList(set); + assertEquals("Sorted order", expected, actual); + } + + // https://issues.apache.org/activemq/browse/AMQ-2630 + class CombyDest implements Queue, Topic, TemporaryQueue, TemporaryTopic { + + private final String qName; + private final String topicName; + + public CombyDest(String qName, String topicName) { + this.qName = qName; + this.topicName = topicName; + } + + public void delete() throws JMSException { + } + + public String getTopicName() throws JMSException { + return topicName; + } + + public String getQueueName() throws JMSException { + return qName; + } + } + + public void testTransformPollymorphic() throws Exception { + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + assertEquals(ActiveMQDestination.transform(queue), queue); + assertTrue("is a q", ActiveMQDestination.transform(new CombyDest(null, "Topic")) instanceof ActiveMQTopic); + assertTrue("is a q", ActiveMQDestination.transform(new CombyDest("Q", null)) instanceof ActiveMQQueue); + try { + ActiveMQDestination.transform(new CombyDest(null, null)); + fail("expect ex as cannot disambiguate"); + } catch (JMSException expected) { + } + try { + ActiveMQDestination.transform(new CombyDest("Q", "T")); + fail("expect ex as cannot disambiguate"); + } catch (JMSException expected) { + } + } + + public static Test suite() { + return suite(ActiveMQDestinationTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void testEmptyQueueName() { + try { + new ActiveMQQueue(""); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + + } + } + + public void testEmptyTopicName() { + try { + new ActiveMQTopic(""); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQMapMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQMapMessageTest.java new file mode 100644 index 0000000000..5b82b2939b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQMapMessageTest.java @@ -0,0 +1,492 @@ +/** + * 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.command; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +import javax.jms.JMSException; +import javax.jms.MessageFormatException; +import javax.jms.MessageNotReadableException; +import javax.jms.MessageNotWriteableException; + +import junit.framework.TestCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ActiveMQMapMessageTest extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(ActiveMQMapMessageTest.class); + + private String name = "testName"; + + /** + * Constructor for ActiveMQMapMessageTest. + * + * @param name + */ + public ActiveMQMapMessageTest(String name) { + super(name); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ActiveMQMapMessageTest.class); + } + + /* + * @see TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + } + + /* + * @see TestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testBytesConversion() throws JMSException, IOException { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + msg.setBoolean("boolean", true); + msg.setByte("byte", (byte)1); + msg.setBytes("bytes", new byte[1]); + msg.setChar("char", 'a'); + msg.setDouble("double", 1.5); + msg.setFloat("float", 1.5f); + msg.setInt("int", 1); + msg.setLong("long", 1); + msg.setObject("object", "stringObj"); + msg.setShort("short", (short)1); + msg.setString("string", "string"); + + // Test with a 1Meg String + StringBuffer bigSB = new StringBuffer(1024 * 1024); + for (int i = 0; i < 1024 * 1024; i++) { + bigSB.append((char)'a' + i % 26); + } + String bigString = bigSB.toString(); + + msg.setString("bigString", bigString); + + msg = (ActiveMQMapMessage)msg.copy(); + + assertEquals(msg.getBoolean("boolean"), true); + assertEquals(msg.getByte("byte"), (byte)1); + assertEquals(msg.getBytes("bytes").length, 1); + assertEquals(msg.getChar("char"), 'a'); + assertEquals(msg.getDouble("double"), 1.5, 0); + assertEquals(msg.getFloat("float"), 1.5f, 0); + assertEquals(msg.getInt("int"), 1); + assertEquals(msg.getLong("long"), 1); + assertEquals(msg.getObject("object"), "stringObj"); + assertEquals(msg.getShort("short"), (short)1); + assertEquals(msg.getString("string"), "string"); + assertEquals(msg.getString("bigString"), bigString); + } + + public void testGetBoolean() throws JMSException { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + msg.setBoolean(name, true); + msg.setReadOnlyBody(true); + assertTrue(msg.getBoolean(name)); + msg.clearBody(); + msg.setString(name, "true"); + + msg = (ActiveMQMapMessage)msg.copy(); + + assertTrue(msg.getBoolean(name)); + } + + public void testGetByte() throws JMSException { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + msg.setByte(this.name, (byte)1); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(msg.getByte(this.name) == (byte)1); + } + + public void testGetShort() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + msg.setShort(this.name, (short)1); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(msg.getShort(this.name) == (short)1); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetChar() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + msg.setChar(this.name, 'a'); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(msg.getChar(this.name) == 'a'); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetInt() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + msg.setInt(this.name, 1); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(msg.getInt(this.name) == 1); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetLong() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + msg.setLong(this.name, 1); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(msg.getLong(this.name) == 1); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetFloat() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + msg.setFloat(this.name, 1.5f); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(msg.getFloat(this.name) == 1.5f); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetDouble() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + msg.setDouble(this.name, 1.5); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(msg.getDouble(this.name) == 1.5); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetString() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + String str = "test"; + msg.setString(this.name, str); + msg = (ActiveMQMapMessage)msg.copy(); + assertEquals(msg.getString(this.name), str); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetBytes() { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + try { + byte[] bytes1 = new byte[3]; + byte[] bytes2 = new byte[2]; + System.arraycopy(bytes1, 0, bytes2, 0, 2); + msg.setBytes(this.name, bytes1); + msg.setBytes(this.name + "2", bytes1, 0, 2); + msg = (ActiveMQMapMessage)msg.copy(); + assertTrue(Arrays.equals(msg.getBytes(this.name), bytes1)); + assertEquals(msg.getBytes(this.name + "2").length, bytes2.length); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testGetObject() throws JMSException { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + Boolean booleanValue = Boolean.TRUE; + Byte byteValue = Byte.valueOf("1"); + byte[] bytesValue = new byte[3]; + Character charValue = new Character('a'); + Double doubleValue = Double.valueOf("1.5"); + Float floatValue = Float.valueOf("1.5"); + Integer intValue = Integer.valueOf("1"); + Long longValue = Long.valueOf("1"); + Short shortValue = Short.valueOf("1"); + String stringValue = "string"; + + try { + msg.setObject("boolean", booleanValue); + msg.setObject("byte", byteValue); + msg.setObject("bytes", bytesValue); + msg.setObject("char", charValue); + msg.setObject("double", doubleValue); + msg.setObject("float", floatValue); + msg.setObject("int", intValue); + msg.setObject("long", longValue); + msg.setObject("short", shortValue); + msg.setObject("string", stringValue); + } catch (MessageFormatException mfe) { + LOG.warn("Caught: " + mfe); + mfe.printStackTrace(); + fail("object formats should be correct"); + } + + msg = (ActiveMQMapMessage)msg.copy(); + + assertTrue(msg.getObject("boolean") instanceof Boolean); + assertEquals(msg.getObject("boolean"), booleanValue); + assertEquals(msg.getBoolean("boolean"), booleanValue.booleanValue()); + assertTrue(msg.getObject("byte") instanceof Byte); + assertEquals(msg.getObject("byte"), byteValue); + assertEquals(msg.getByte("byte"), byteValue.byteValue()); + assertTrue(msg.getObject("bytes") instanceof byte[]); + assertEquals(((byte[])msg.getObject("bytes")).length, bytesValue.length); + assertEquals(msg.getBytes("bytes").length, bytesValue.length); + assertTrue(msg.getObject("char") instanceof Character); + assertEquals(msg.getObject("char"), charValue); + assertEquals(msg.getChar("char"), charValue.charValue()); + assertTrue(msg.getObject("double") instanceof Double); + assertEquals(msg.getObject("double"), doubleValue); + assertEquals(msg.getDouble("double"), doubleValue.doubleValue(), 0); + assertTrue(msg.getObject("float") instanceof Float); + assertEquals(msg.getObject("float"), floatValue); + assertEquals(msg.getFloat("float"), floatValue.floatValue(), 0); + assertTrue(msg.getObject("int") instanceof Integer); + assertEquals(msg.getObject("int"), intValue); + assertEquals(msg.getInt("int"), intValue.intValue()); + assertTrue(msg.getObject("long") instanceof Long); + assertEquals(msg.getObject("long"), longValue); + assertEquals(msg.getLong("long"), longValue.longValue()); + assertTrue(msg.getObject("short") instanceof Short); + assertEquals(msg.getObject("short"), shortValue); + assertEquals(msg.getShort("short"), shortValue.shortValue()); + assertTrue(msg.getObject("string") instanceof String); + assertEquals(msg.getObject("string"), stringValue); + assertEquals(msg.getString("string"), stringValue); + + msg.clearBody(); + try { + msg.setObject("object", new Object()); + fail("should have thrown exception"); + } catch (MessageFormatException e) { + } + + } + + public void testGetMapNames() throws JMSException { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + msg.setBoolean("boolean", true); + msg.setByte("byte", (byte)1); + msg.setBytes("bytes1", new byte[1]); + msg.setBytes("bytes2", new byte[3], 0, 2); + msg.setChar("char", 'a'); + msg.setDouble("double", 1.5); + msg.setFloat("float", 1.5f); + msg.setInt("int", 1); + msg.setLong("long", 1); + msg.setObject("object", "stringObj"); + msg.setShort("short", (short)1); + msg.setString("string", "string"); + + msg = (ActiveMQMapMessage)msg.copy(); + + Enumeration mapNamesEnum = msg.getMapNames(); + List mapNamesList = Collections.list(mapNamesEnum); + + assertEquals(mapNamesList.size(), 12); + assertTrue(mapNamesList.contains("boolean")); + assertTrue(mapNamesList.contains("byte")); + assertTrue(mapNamesList.contains("bytes1")); + assertTrue(mapNamesList.contains("bytes2")); + assertTrue(mapNamesList.contains("char")); + assertTrue(mapNamesList.contains("double")); + assertTrue(mapNamesList.contains("float")); + assertTrue(mapNamesList.contains("int")); + assertTrue(mapNamesList.contains("long")); + assertTrue(mapNamesList.contains("object")); + assertTrue(mapNamesList.contains("short")); + assertTrue(mapNamesList.contains("string")); + } + + public void testItemExists() throws JMSException { + ActiveMQMapMessage mapMessage = new ActiveMQMapMessage(); + + mapMessage.setString("exists", "test"); + + mapMessage = (ActiveMQMapMessage)mapMessage.copy(); + + assertTrue(mapMessage.itemExists("exists")); + assertFalse(mapMessage.itemExists("doesntExist")); + } + + public void testClearBody() throws JMSException { + ActiveMQMapMessage mapMessage = new ActiveMQMapMessage(); + mapMessage.setString("String", "String"); + mapMessage.clearBody(); + assertFalse(mapMessage.isReadOnlyBody()); + + mapMessage.onSend(); + mapMessage.setContent(mapMessage.getContent()); + assertNull(mapMessage.getString("String")); + mapMessage.clearBody(); + mapMessage.setString("String", "String"); + + mapMessage = (ActiveMQMapMessage)mapMessage.copy(); + + mapMessage.getString("String"); + } + + public void testReadOnlyBody() throws JMSException { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + msg.setBoolean("boolean", true); + msg.setByte("byte", (byte)1); + msg.setBytes("bytes", new byte[1]); + msg.setBytes("bytes2", new byte[3], 0, 2); + msg.setChar("char", 'a'); + msg.setDouble("double", 1.5); + msg.setFloat("float", 1.5f); + msg.setInt("int", 1); + msg.setLong("long", 1); + msg.setObject("object", "stringObj"); + msg.setShort("short", (short)1); + msg.setString("string", "string"); + + msg.setReadOnlyBody(true); + + try { + msg.getBoolean("boolean"); + msg.getByte("byte"); + msg.getBytes("bytes"); + msg.getChar("char"); + msg.getDouble("double"); + msg.getFloat("float"); + msg.getInt("int"); + msg.getLong("long"); + msg.getObject("object"); + msg.getShort("short"); + msg.getString("string"); + } catch (MessageNotReadableException mnre) { + fail("should be readable"); + } + try { + msg.setBoolean("boolean", true); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setByte("byte", (byte)1); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setBytes("bytes", new byte[1]); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setBytes("bytes2", new byte[3], 0, 2); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setChar("char", 'a'); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setDouble("double", 1.5); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setFloat("float", 1.5f); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setInt("int", 1); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setLong("long", 1); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setObject("object", "stringObj"); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setShort("short", (short)1); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + msg.setString("string", "string"); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + } + + public void testWriteOnlyBody() throws JMSException { + ActiveMQMapMessage msg = new ActiveMQMapMessage(); + msg.setReadOnlyBody(false); + + msg.setBoolean("boolean", true); + msg.setByte("byte", (byte)1); + msg.setBytes("bytes", new byte[1]); + msg.setBytes("bytes2", new byte[3], 0, 2); + msg.setChar("char", 'a'); + msg.setDouble("double", 1.5); + msg.setFloat("float", 1.5f); + msg.setInt("int", 1); + msg.setLong("long", 1); + msg.setObject("object", "stringObj"); + msg.setShort("short", (short)1); + msg.setString("string", "string"); + + msg.setReadOnlyBody(true); + + msg.getBoolean("boolean"); + msg.getByte("byte"); + msg.getBytes("bytes"); + msg.getChar("char"); + msg.getDouble("double"); + msg.getFloat("float"); + msg.getInt("int"); + msg.getLong("long"); + msg.getObject("object"); + msg.getShort("short"); + msg.getString("string"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQMessageTest.java new file mode 100644 index 0000000000..e1079a1628 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQMessageTest.java @@ -0,0 +1,992 @@ +/** + * 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.command; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Map; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageFormatException; +import javax.jms.MessageNotWriteableException; + +import junit.framework.TestCase; + +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.state.CommandVisitor; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.wireformat.WireFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ActiveMQMessageTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ActiveMQMessageTest.class); + + protected boolean readOnlyMessage; + + private String jmsMessageID; + private String jmsCorrelationID; + private ActiveMQDestination jmsDestination; + private ActiveMQDestination jmsReplyTo; + private int jmsDeliveryMode; + private boolean jmsRedelivered; + private String jmsType; + private long jmsExpiration; + private int jmsPriority; + private long jmsTimestamp; + private long[] consumerIDs; + + /** + * Constructor for ActiveMQMessageTest. + * + * @param name + */ + public ActiveMQMessageTest(String name) { + super(name); + } + + public static void main(String[] args) { + } + + /* + * @see TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + this.jmsMessageID = "ID:TEST-ID:0:0:0:1"; + this.jmsCorrelationID = "testcorrelationid"; + this.jmsDestination = new ActiveMQTopic("test.topic"); + this.jmsReplyTo = new ActiveMQTempTopic("test.replyto.topic:001"); + this.jmsDeliveryMode = Message.DEFAULT_DELIVERY_MODE; + this.jmsRedelivered = true; + this.jmsType = "test type"; + this.jmsExpiration = 100000; + this.jmsPriority = 5; + this.jmsTimestamp = System.currentTimeMillis(); + this.readOnlyMessage = false; + this.consumerIDs = new long[3]; + for (int i = 0; i < this.consumerIDs.length; i++) { + this.consumerIDs[i] = i; + } + } + + /* + * @see TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testGetDataStructureType() { + ActiveMQMessage msg = new ActiveMQMessage(); + assertEquals(msg.getDataStructureType(), CommandTypes.ACTIVEMQ_MESSAGE); + } + + public void testHashCode() throws Exception { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSMessageID(this.jmsMessageID); + assertTrue(msg.getJMSMessageID().hashCode() == jmsMessageID.hashCode()); + } + + public void testSetReadOnly() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setReadOnlyProperties(true); + boolean test = false; + try { + msg.setIntProperty("test", 1); + } catch (MessageNotWriteableException me) { + test = true; + } catch (JMSException e) { + e.printStackTrace(System.err); + test = false; + } + assertTrue(test); + } + + public void testSetToForeignJMSID() throws Exception { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSMessageID("ID:EMS-SERVER.8B443C380083:429"); + } + + /* + * Class to test for boolean equals(Object) + */ + public void testEqualsObject() throws Exception { + ActiveMQMessage msg1 = new ActiveMQMessage(); + ActiveMQMessage msg2 = new ActiveMQMessage(); + msg1.setJMSMessageID(this.jmsMessageID); + assertTrue(!msg1.equals(msg2)); + msg2.setJMSMessageID(this.jmsMessageID); + assertTrue(msg1.equals(msg2)); + } + + public void testShallowCopy() throws Exception { + ActiveMQMessage msg1 = new ActiveMQMessage(); + msg1.setJMSMessageID(jmsMessageID); + ActiveMQMessage msg2 = (ActiveMQMessage) msg1.copy(); + assertTrue(msg1 != msg2 && msg1.equals(msg2)); + } + + public void testCopy() throws Exception { + this.jmsMessageID = "testid"; + this.jmsCorrelationID = "testcorrelationid"; + this.jmsDestination = new ActiveMQTopic("test.topic"); + this.jmsReplyTo = new ActiveMQTempTopic("test.replyto.topic:001"); + this.jmsDeliveryMode = Message.DEFAULT_DELIVERY_MODE; + this.jmsRedelivered = true; + this.jmsType = "test type"; + this.jmsExpiration = 100000; + this.jmsPriority = 5; + this.jmsTimestamp = System.currentTimeMillis(); + this.readOnlyMessage = false; + + ActiveMQMessage msg1 = new ActiveMQMessage(); + msg1.setJMSMessageID(this.jmsMessageID); + msg1.setJMSCorrelationID(this.jmsCorrelationID); + msg1.setJMSDestination(this.jmsDestination); + msg1.setJMSReplyTo(this.jmsReplyTo); + msg1.setJMSDeliveryMode(this.jmsDeliveryMode); + msg1.setJMSRedelivered(this.jmsRedelivered); + msg1.setJMSType(this.jmsType); + msg1.setJMSExpiration(this.jmsExpiration); + msg1.setJMSPriority(this.jmsPriority); + msg1.setJMSTimestamp(this.jmsTimestamp); + msg1.setReadOnlyProperties(true); + ActiveMQMessage msg2 = new ActiveMQMessage(); + msg1.copy(msg2); + assertEquals(msg1.getJMSMessageID(), msg2.getJMSMessageID()); + assertTrue(msg1.getJMSCorrelationID().equals(msg2.getJMSCorrelationID())); + assertTrue(msg1.getJMSDestination().equals(msg2.getJMSDestination())); + assertTrue(msg1.getJMSReplyTo().equals(msg2.getJMSReplyTo())); + assertTrue(msg1.getJMSDeliveryMode() == msg2.getJMSDeliveryMode()); + assertTrue(msg1.getJMSRedelivered() == msg2.getJMSRedelivered()); + assertTrue(msg1.getJMSType().equals(msg2.getJMSType())); + assertTrue(msg1.getJMSExpiration() == msg2.getJMSExpiration()); + assertTrue(msg1.getJMSPriority() == msg2.getJMSPriority()); + assertTrue(msg1.getJMSTimestamp() == msg2.getJMSTimestamp()); + + LOG.info("Message is: " + msg1); + } + + public void testGetAndSetJMSMessageID() throws Exception { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSMessageID(this.jmsMessageID); + assertEquals(msg.getJMSMessageID(), this.jmsMessageID); + } + + public void testGetAndSetJMSTimestamp() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSTimestamp(this.jmsTimestamp); + assertTrue(msg.getJMSTimestamp() == this.jmsTimestamp); + } + + public void testGetJMSCorrelationIDAsBytes() throws Exception { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSCorrelationID(this.jmsCorrelationID); + byte[] testbytes = msg.getJMSCorrelationIDAsBytes(); + String str2 = new String(testbytes); + assertTrue(this.jmsCorrelationID.equals(str2)); + } + + public void testSetJMSCorrelationIDAsBytes() throws Exception { + ActiveMQMessage msg = new ActiveMQMessage(); + byte[] testbytes = this.jmsCorrelationID.getBytes(); + msg.setJMSCorrelationIDAsBytes(testbytes); + testbytes = msg.getJMSCorrelationIDAsBytes(); + String str2 = new String(testbytes); + assertTrue(this.jmsCorrelationID.equals(str2)); + } + + public void testGetAndSetJMSCorrelationID() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSCorrelationID(this.jmsCorrelationID); + assertTrue(msg.getJMSCorrelationID().equals(this.jmsCorrelationID)); + } + + public void testGetAndSetJMSReplyTo() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSReplyTo(this.jmsReplyTo); + assertTrue(msg.getJMSReplyTo().equals(this.jmsReplyTo)); + } + + public void testGetAndSetJMSDestination() throws Exception { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSDestination(this.jmsDestination); + assertTrue(msg.getJMSDestination().equals(this.jmsDestination)); + } + + public void testGetAndSetJMSDeliveryMode() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSDeliveryMode(this.jmsDeliveryMode); + assertTrue(msg.getJMSDeliveryMode() == this.jmsDeliveryMode); + } + + public void testGetAndSetMSRedelivered() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSRedelivered(this.jmsRedelivered); + assertTrue(msg.getJMSRedelivered() == this.jmsRedelivered); + } + + public void testGetAndSetJMSType() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSType(this.jmsType); + assertTrue(msg.getJMSType().equals(this.jmsType)); + } + + public void testGetAndSetJMSExpiration() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSExpiration(this.jmsExpiration); + assertTrue(msg.getJMSExpiration() == this.jmsExpiration); + } + + public void testGetAndSetJMSPriority() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSPriority(this.jmsPriority); + assertTrue(msg.getJMSPriority() == this.jmsPriority); + + msg.setJMSPriority(-90); + assertEquals(0, msg.getJMSPriority()); + + msg.setJMSPriority(90); + assertEquals(9, msg.getJMSPriority()); + } + + public void testClearProperties() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setStringProperty("test", "test"); + msg.setContent(new ByteSequence(new byte[1], 0, 0)); + msg.setJMSMessageID(this.jmsMessageID); + msg.clearProperties(); + assertNull(msg.getStringProperty("test")); + assertNotNull(msg.getJMSMessageID()); + assertNotNull(msg.getContent()); + } + + public void testPropertyExists() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setStringProperty("test", "test"); + assertTrue(msg.propertyExists("test")); + + msg.setIntProperty("JMSXDeliveryCount", 1); + assertTrue(msg.propertyExists("JMSXDeliveryCount")); + } + + public void testGetBooleanProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "booleanProperty"; + msg.setBooleanProperty(name, true); + assertTrue(msg.getBooleanProperty(name)); + } + + public void testGetByteProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "byteProperty"; + msg.setByteProperty(name, (byte) 1); + assertTrue(msg.getByteProperty(name) == 1); + } + + public void testGetShortProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "shortProperty"; + msg.setShortProperty(name, (short) 1); + assertTrue(msg.getShortProperty(name) == 1); + } + + public void testGetIntProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "intProperty"; + msg.setIntProperty(name, 1); + assertTrue(msg.getIntProperty(name) == 1); + } + + public void testGetLongProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "longProperty"; + msg.setLongProperty(name, 1); + assertTrue(msg.getLongProperty(name) == 1); + } + + public void testGetFloatProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "floatProperty"; + msg.setFloatProperty(name, 1.3f); + assertTrue(msg.getFloatProperty(name) == 1.3f); + } + + public void testGetDoubleProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "doubleProperty"; + msg.setDoubleProperty(name, 1.3d); + assertTrue(msg.getDoubleProperty(name) == 1.3); + } + + public void testGetStringProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "stringProperty"; + msg.setStringProperty(name, name); + assertTrue(msg.getStringProperty(name).equals(name)); + } + + public void testGetObjectProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "floatProperty"; + msg.setFloatProperty(name, 1.3f); + assertTrue(msg.getObjectProperty(name) instanceof Float); + assertTrue(((Float) msg.getObjectProperty(name)).floatValue() == 1.3f); + } + + public void testSetJMSDeliveryModeProperty() throws JMSException { + ActiveMQMessage message = new ActiveMQMessage(); + String propertyName = "JMSDeliveryMode"; + + // Set as Boolean + message.setObjectProperty(propertyName, Boolean.TRUE); + assertTrue(message.isPersistent()); + message.setObjectProperty(propertyName, Boolean.FALSE); + assertFalse(message.isPersistent()); + message.setBooleanProperty(propertyName, true); + assertTrue(message.isPersistent()); + message.setBooleanProperty(propertyName, false); + assertFalse(message.isPersistent()); + + // Set as Integer + message.setObjectProperty(propertyName, DeliveryMode.PERSISTENT); + assertTrue(message.isPersistent()); + message.setObjectProperty(propertyName, DeliveryMode.NON_PERSISTENT); + assertFalse(message.isPersistent()); + message.setIntProperty(propertyName, DeliveryMode.PERSISTENT); + assertTrue(message.isPersistent()); + message.setIntProperty(propertyName, DeliveryMode.NON_PERSISTENT); + assertFalse(message.isPersistent()); + + // Set as String + message.setObjectProperty(propertyName, "PERSISTENT"); + assertTrue(message.isPersistent()); + message.setObjectProperty(propertyName, "NON_PERSISTENT"); + assertFalse(message.isPersistent()); + message.setStringProperty(propertyName, "PERSISTENT"); + assertTrue(message.isPersistent()); + message.setStringProperty(propertyName, "NON_PERSISTENT"); + assertFalse(message.isPersistent()); + } + + @SuppressWarnings("rawtypes") + public void testGetPropertyNames() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name1 = "floatProperty"; + msg.setFloatProperty(name1, 1.3f); + String name2 = "JMSXDeliveryCount"; + msg.setIntProperty(name2, 1); + String name3 = "JMSRedelivered"; + msg.setBooleanProperty(name3, false); + boolean found1 = false; + boolean found2 = false; + boolean found3 = false; + for (Enumeration iter = msg.getPropertyNames(); iter.hasMoreElements();) { + Object element = iter.nextElement(); + found1 |= element.equals(name1); + found2 |= element.equals(name2); + found3 |= element.equals(name3); + } + assertTrue("prop name1 found", found1); + // spec compliance, only non JMS (and JMSX) props returned + assertFalse("prop name2 not found", found2); + assertFalse("prop name4 not found", found3); + } + + @SuppressWarnings("rawtypes") + public void testGetAllPropertyNames() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name1 = "floatProperty"; + msg.setFloatProperty(name1, 1.3f); + String name2 = "JMSXDeliveryCount"; + msg.setIntProperty(name2, 1); + String name3 = "JMSRedelivered"; + msg.setBooleanProperty(name3, false); + boolean found1 = false; + boolean found2 = false; + boolean found3 = false; + for (Enumeration iter = msg.getAllPropertyNames(); iter.hasMoreElements();) { + Object element = iter.nextElement(); + found1 |= element.equals(name1); + found2 |= element.equals(name2); + found3 |= element.equals(name3); + } + assertTrue("prop name1 found", found1); + assertTrue("prop name2 found", found2); + assertTrue("prop name4 found", found3); + } + + public void testSetObjectProperty() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String name = "property"; + + try { + msg.setObjectProperty(name, "string"); + msg.setObjectProperty(name, Byte.valueOf("1")); + msg.setObjectProperty(name, Short.valueOf("1")); + msg.setObjectProperty(name, Integer.valueOf("1")); + msg.setObjectProperty(name, Long.valueOf("1")); + msg.setObjectProperty(name, Float.valueOf("1.1f")); + msg.setObjectProperty(name, Double.valueOf("1.1")); + msg.setObjectProperty(name, Boolean.TRUE); + msg.setObjectProperty(name, null); + } catch (MessageFormatException e) { + fail("should accept object primitives and String"); + } + try { + msg.setObjectProperty(name, new byte[5]); + fail("should accept only object primitives and String"); + } catch (MessageFormatException e) { + } + try { + msg.setObjectProperty(name, new Object()); + fail("should accept only object primitives and String"); + } catch (MessageFormatException e) { + } + } + + public void testConvertProperties() throws Exception { + org.apache.activemq.command.Message msg = new org.apache.activemq.command.Message() { + @Override + public org.apache.activemq.command.Message copy() { + return null; + } + + @Override + public void beforeMarshall(WireFormat wireFormat) throws IOException { + super.beforeMarshall(wireFormat); + } + + @Override + public byte getDataStructureType() { + return 0; + } + + @Override + public Response visit(CommandVisitor visitor) throws Exception { + return null; + } + + @Override + public void clearBody() throws JMSException { + } + + @Override + public void storeContent() { + } + + @Override + public void storeContentAndClear() { + + } + }; + + msg.setProperty("stringProperty", "string"); + msg.setProperty("byteProperty", Byte.valueOf("1")); + msg.setProperty("shortProperty", Short.valueOf("1")); + msg.setProperty("intProperty", Integer.valueOf("1")); + msg.setProperty("longProperty", Long.valueOf("1")); + msg.setProperty("floatProperty", Float.valueOf("1.1f")); + msg.setProperty("doubleProperty", Double.valueOf("1.1")); + msg.setProperty("booleanProperty", Boolean.TRUE); + msg.setProperty("nullProperty", null); + + msg.beforeMarshall(new OpenWireFormat()); + + Map properties = msg.getProperties(); + assertEquals(properties.get("stringProperty"), "string"); + assertEquals(((Byte) properties.get("byteProperty")).byteValue(), 1); + assertEquals(((Short) properties.get("shortProperty")).shortValue(), 1); + assertEquals(((Integer) properties.get("intProperty")).intValue(), 1); + assertEquals(((Long) properties.get("longProperty")).longValue(), 1); + assertEquals(((Float) properties.get("floatProperty")).floatValue(), 1.1f, 0); + assertEquals(((Double) properties.get("doubleProperty")).doubleValue(), 1.1, 0); + assertEquals(((Boolean) properties.get("booleanProperty")).booleanValue(), true); + assertNull(properties.get("nullProperty")); + } + + public void testSetNullProperty() throws JMSException { + Message msg = new ActiveMQMessage(); + String name = "cheese"; + msg.setStringProperty(name, "Cheddar"); + assertEquals("Cheddar", msg.getStringProperty(name)); + + msg.setStringProperty(name, null); + assertEquals(null, msg.getStringProperty(name)); + } + + public void testSetNullPropertyName() throws JMSException { + Message msg = new ActiveMQMessage(); + + try { + msg.setStringProperty(null, "Cheese"); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + LOG.info("Worked, caught: " + e); + } + } + + public void testSetEmptyPropertyName() throws JMSException { + Message msg = new ActiveMQMessage(); + + try { + msg.setStringProperty("", "Cheese"); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + LOG.info("Worked, caught: " + e); + } + } + + public void testGetAndSetJMSXDeliveryCount() throws JMSException { + Message msg = new ActiveMQMessage(); + msg.setIntProperty("JMSXDeliveryCount", 1); + int count = msg.getIntProperty("JMSXDeliveryCount"); + assertTrue("expected delivery count = 1 - got: " + count, count == 1); + } + + public void testClearBody() throws JMSException { + ActiveMQBytesMessage message = new ActiveMQBytesMessage(); + message.clearBody(); + assertFalse(message.isReadOnlyBody()); + assertNull(message.getContent()); + } + + public void testBooleanPropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setBooleanProperty(propertyName, true); + + assertEquals(((Boolean) msg.getObjectProperty(propertyName)).booleanValue(), true); + assertTrue(msg.getBooleanProperty(propertyName)); + assertEquals(msg.getStringProperty(propertyName), "true"); + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getShortProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getIntProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getLongProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getDoubleProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + } + + public void testBytePropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setByteProperty(propertyName, (byte) 1); + + assertEquals(((Byte) msg.getObjectProperty(propertyName)).byteValue(), 1); + assertEquals(msg.getByteProperty(propertyName), 1); + assertEquals(msg.getShortProperty(propertyName), 1); + assertEquals(msg.getIntProperty(propertyName), 1); + assertEquals(msg.getLongProperty(propertyName), 1); + assertEquals(msg.getStringProperty(propertyName), "1"); + try { + msg.getBooleanProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getDoubleProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + } + + public void testShortPropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setShortProperty(propertyName, (short) 1); + + assertEquals(((Short) msg.getObjectProperty(propertyName)).shortValue(), 1); + assertEquals(msg.getShortProperty(propertyName), 1); + assertEquals(msg.getIntProperty(propertyName), 1); + assertEquals(msg.getLongProperty(propertyName), 1); + assertEquals(msg.getStringProperty(propertyName), "1"); + try { + msg.getBooleanProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getDoubleProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + } + + public void testIntPropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setIntProperty(propertyName, 1); + + assertEquals(((Integer) msg.getObjectProperty(propertyName)).intValue(), 1); + assertEquals(msg.getIntProperty(propertyName), 1); + assertEquals(msg.getLongProperty(propertyName), 1); + assertEquals(msg.getStringProperty(propertyName), "1"); + try { + msg.getBooleanProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getShortProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getDoubleProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + } + + public void testLongPropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setLongProperty(propertyName, 1); + + assertEquals(((Long) msg.getObjectProperty(propertyName)).longValue(), 1); + assertEquals(msg.getLongProperty(propertyName), 1); + assertEquals(msg.getStringProperty(propertyName), "1"); + try { + msg.getBooleanProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getShortProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getIntProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getDoubleProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + } + + public void testFloatPropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setFloatProperty(propertyName, (float) 1.5); + assertEquals(((Float) msg.getObjectProperty(propertyName)).floatValue(), 1.5, 0); + assertEquals(msg.getFloatProperty(propertyName), 1.5, 0); + assertEquals(msg.getDoubleProperty(propertyName), 1.5, 0); + assertEquals(msg.getStringProperty(propertyName), "1.5"); + try { + msg.getBooleanProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getShortProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getIntProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getLongProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + } + + public void testDoublePropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setDoubleProperty(propertyName, 1.5); + assertEquals(((Double) msg.getObjectProperty(propertyName)).doubleValue(), 1.5, 0); + assertEquals(msg.getDoubleProperty(propertyName), 1.5, 0); + assertEquals(msg.getStringProperty(propertyName), "1.5"); + try { + msg.getBooleanProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getShortProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getIntProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getLongProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + } + + public void testStringPropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + String stringValue = "true"; + msg.setStringProperty(propertyName, stringValue); + assertEquals(msg.getStringProperty(propertyName), stringValue); + assertEquals((String) msg.getObjectProperty(propertyName), stringValue); + assertEquals(msg.getBooleanProperty(propertyName), true); + + stringValue = "1"; + msg.setStringProperty(propertyName, stringValue); + assertEquals(msg.getByteProperty(propertyName), 1); + assertEquals(msg.getShortProperty(propertyName), 1); + assertEquals(msg.getIntProperty(propertyName), 1); + assertEquals(msg.getLongProperty(propertyName), 1); + + stringValue = "1.5"; + msg.setStringProperty(propertyName, stringValue); + assertEquals(msg.getFloatProperty(propertyName), 1.5, 0); + assertEquals(msg.getDoubleProperty(propertyName), 1.5, 0); + + stringValue = "bad"; + msg.setStringProperty(propertyName, stringValue); + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (NumberFormatException e) { + } + try { + msg.getShortProperty(propertyName); + fail("Should have thrown exception"); + } catch (NumberFormatException e) { + } + try { + msg.getIntProperty(propertyName); + fail("Should have thrown exception"); + } catch (NumberFormatException e) { + } + try { + msg.getLongProperty(propertyName); + fail("Should have thrown exception"); + } catch (NumberFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (NumberFormatException e) { + } + try { + msg.getDoubleProperty(propertyName); + fail("Should have thrown exception"); + } catch (NumberFormatException e) { + } + assertFalse(msg.getBooleanProperty(propertyName)); + } + + public void testObjectPropertyConversion() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + Object obj = new Object(); + try { + ((org.apache.activemq.command.Message) msg).setProperty(propertyName, obj); // bypass + // object + // check + } catch (IOException e) { + } + try { + msg.getStringProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getBooleanProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getByteProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getShortProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getIntProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getLongProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getFloatProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + try { + msg.getDoubleProperty(propertyName); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + + } + + public void testReadOnlyProperties() throws JMSException { + ActiveMQMessage msg = new ActiveMQMessage(); + String propertyName = "property"; + msg.setReadOnlyProperties(true); + + try { + msg.setObjectProperty(propertyName, new Object()); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setStringProperty(propertyName, "test"); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setBooleanProperty(propertyName, true); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setByteProperty(propertyName, (byte) 1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setShortProperty(propertyName, (short) 1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setIntProperty(propertyName, 1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setLongProperty(propertyName, 1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setFloatProperty(propertyName, (float) 1.5); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + try { + msg.setDoubleProperty(propertyName, 1.5); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException e) { + } + } + + public void testIsExpired() { + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setJMSExpiration(System.currentTimeMillis() - 1); + assertTrue(msg.isExpired()); + msg.setJMSExpiration(System.currentTimeMillis() + 10000); + assertFalse(msg.isExpired()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQObjectMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQObjectMessageTest.java new file mode 100644 index 0000000000..fc38a30e83 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQObjectMessageTest.java @@ -0,0 +1,126 @@ +/** + * 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.command; + +import java.io.IOException; + +import javax.jms.JMSException; +import javax.jms.MessageNotReadableException; +import javax.jms.MessageNotWriteableException; + +import junit.framework.TestCase; + +/** + * + */ +public class ActiveMQObjectMessageTest extends TestCase { + + /** + * Constructor for ActiveMQObjectMessageTest. + * + * @param name + */ + public ActiveMQObjectMessageTest(String name) { + super(name); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ActiveMQObjectMessageTest.class); + } + + /* + * @see TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + } + + /* + * @see TestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testBytes() throws JMSException, IOException { + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + String str = "testText"; + msg.setObject(str); + + msg = (ActiveMQObjectMessage) msg.copy(); + assertEquals(msg.getObject(), str); + + } + + public void testSetObject() throws JMSException { + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + String str = "testText"; + msg.setObject(str); + assertTrue(msg.getObject() == str); + } + + public void testClearBody() throws JMSException { + ActiveMQObjectMessage objectMessage = new ActiveMQObjectMessage(); + try { + objectMessage.setObject("String"); + objectMessage.clearBody(); + assertFalse(objectMessage.isReadOnlyBody()); + assertNull(objectMessage.getObject()); + objectMessage.setObject("String"); + objectMessage.getObject(); + } catch (MessageNotWriteableException mnwe) { + fail("should be writeable"); + } + } + + public void testReadOnlyBody() throws JMSException { + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + msg.setObject("test"); + msg.setReadOnlyBody(true); + try { + msg.getObject(); + } catch (MessageNotReadableException e) { + fail("should be readable"); + } + try { + msg.setObject("test"); + fail("should throw exception"); + } catch (MessageNotWriteableException e) { + } + } + + public void testWriteOnlyBody() throws JMSException { // should always be readable + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + msg.setReadOnlyBody(false); + try { + msg.setObject("test"); + msg.getObject(); + } catch (MessageNotReadableException e) { + fail("should be readable"); + } + msg.setReadOnlyBody(true); + try { + msg.getObject(); + msg.setObject("test"); + fail("should throw exception"); + } catch (MessageNotReadableException e) { + fail("should be readable"); + } catch (MessageNotWriteableException mnwe) { + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQStreamMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQStreamMessageTest.java new file mode 100644 index 0000000000..9e0f468416 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQStreamMessageTest.java @@ -0,0 +1,1000 @@ +/** + * 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.command; + +import java.io.Serializable; + +import javax.jms.JMSException; +import javax.jms.MessageFormatException; +import javax.jms.MessageNotReadableException; +import javax.jms.MessageNotWriteableException; + +import junit.framework.TestCase; + +/** + * + */ +public class ActiveMQStreamMessageTest extends TestCase { + + /** + * Constructor for ActiveMQStreamMessageTest. + * + * @param name + */ + public ActiveMQStreamMessageTest(String name) { + super(name); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ActiveMQStreamMessageTest.class); + } + + /* + * @see TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + } + + /* + * @see TestCase#tearDown() + */ + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testGetDataStructureType() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + assertEquals(msg.getDataStructureType(), CommandTypes.ACTIVEMQ_STREAM_MESSAGE); + } + + public void testReadBoolean() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + msg.writeBoolean(true); + msg.reset(); + assertTrue(msg.readBoolean()); + msg.reset(); + assertTrue(msg.readString().equals("true")); + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readShort(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readInt(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readLong(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readDouble(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testreadByte() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + byte test = (byte)4; + msg.writeByte(test); + msg.reset(); + assertTrue(msg.readByte() == test); + msg.reset(); + assertTrue(msg.readShort() == test); + msg.reset(); + assertTrue(msg.readInt() == test); + msg.reset(); + assertTrue(msg.readLong() == test); + msg.reset(); + assertTrue(msg.readString().equals(new Byte(test).toString())); + msg.reset(); + try { + msg.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readDouble(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadShort() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + short test = (short)4; + msg.writeShort(test); + msg.reset(); + assertTrue(msg.readShort() == test); + msg.reset(); + assertTrue(msg.readInt() == test); + msg.reset(); + assertTrue(msg.readLong() == test); + msg.reset(); + assertTrue(msg.readString().equals(new Short(test).toString())); + msg.reset(); + try { + msg.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readDouble(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadChar() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + char test = 'z'; + msg.writeChar(test); + msg.reset(); + assertTrue(msg.readChar() == test); + msg.reset(); + assertTrue(msg.readString().equals(new Character(test).toString())); + msg.reset(); + try { + msg.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readShort(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readInt(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readLong(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readDouble(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadInt() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + int test = 4; + msg.writeInt(test); + msg.reset(); + assertTrue(msg.readInt() == test); + msg.reset(); + assertTrue(msg.readLong() == test); + msg.reset(); + assertTrue(msg.readString().equals(new Integer(test).toString())); + msg.reset(); + try { + msg.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readShort(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readDouble(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadLong() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + long test = 4L; + msg.writeLong(test); + msg.reset(); + assertTrue(msg.readLong() == test); + msg.reset(); + assertTrue(msg.readString().equals(Long.valueOf(test).toString())); + msg.reset(); + try { + msg.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readShort(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readInt(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readDouble(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg = new ActiveMQStreamMessage(); + msg.writeObject(new Long("1")); + // reset so it's readable now + msg.reset(); + assertEquals(new Long("1"), msg.readObject()); + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadFloat() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + float test = 4.4f; + msg.writeFloat(test); + msg.reset(); + assertTrue(msg.readFloat() == test); + msg.reset(); + assertTrue(msg.readDouble() == test); + msg.reset(); + assertTrue(msg.readString().equals(new Float(test).toString())); + msg.reset(); + try { + msg.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readShort(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readInt(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readLong(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadDouble() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + double test = 4.4d; + msg.writeDouble(test); + msg.reset(); + assertTrue(msg.readDouble() == test); + msg.reset(); + assertTrue(msg.readString().equals(new Double(test).toString())); + msg.reset(); + try { + msg.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readShort(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readInt(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readLong(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + + } + + public void testReadString() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + byte testByte = (byte)2; + msg.writeString(new Byte(testByte).toString()); + msg.reset(); + assertTrue(msg.readByte() == testByte); + msg.clearBody(); + short testShort = 3; + msg.writeString(new Short(testShort).toString()); + msg.reset(); + assertTrue(msg.readShort() == testShort); + msg.clearBody(); + int testInt = 4; + msg.writeString(new Integer(testInt).toString()); + msg.reset(); + assertTrue(msg.readInt() == testInt); + msg.clearBody(); + long testLong = 6L; + msg.writeString(new Long(testLong).toString()); + msg.reset(); + assertTrue(msg.readLong() == testLong); + msg.clearBody(); + float testFloat = 6.6f; + msg.writeString(new Float(testFloat).toString()); + msg.reset(); + assertTrue(msg.readFloat() == testFloat); + msg.clearBody(); + double testDouble = 7.7d; + msg.writeString(new Double(testDouble).toString()); + msg.reset(); + assertTrue(msg.readDouble() == testDouble); + msg.clearBody(); + msg.writeString("true"); + msg.reset(); + assertTrue(msg.readBoolean()); + msg.clearBody(); + msg.writeString("a"); + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + msg.clearBody(); + msg.writeString("777"); + msg.reset(); + try { + msg.readBytes(new byte[3]); + fail("Should have thrown exception"); + } catch (MessageFormatException e) { + } + + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadBigString() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + // Test with a 1Meg String + StringBuffer bigSB = new StringBuffer(1024 * 1024); + for (int i = 0; i < 1024 * 1024; i++) { + bigSB.append((char)'a' + i % 26); + } + String bigString = bigSB.toString(); + + msg.writeString(bigString); + msg.reset(); + assertEquals(bigString, msg.readString()); + + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadBytes() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + byte[] test = new byte[50]; + for (int i = 0; i < test.length; i++) { + test[i] = (byte)i; + } + msg.writeBytes(test); + msg.reset(); + byte[] valid = new byte[test.length]; + msg.readBytes(valid); + for (int i = 0; i < valid.length; i++) { + assertTrue(valid[i] == test[i]); + } + msg.reset(); + try { + msg.readByte(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readShort(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readInt(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readLong(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readFloat(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readChar(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + msg.reset(); + try { + msg.readString(); + fail("Should have thrown exception"); + } catch (MessageFormatException mfe) { + } + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testReadObject() { + ActiveMQStreamMessage msg = new ActiveMQStreamMessage(); + try { + byte testByte = (byte)2; + msg.writeByte(testByte); + msg.reset(); + assertTrue(((Byte)msg.readObject()).byteValue() == testByte); + msg.clearBody(); + + short testShort = 3; + msg.writeShort(testShort); + msg.reset(); + assertTrue(((Short)msg.readObject()).shortValue() == testShort); + msg.clearBody(); + + int testInt = 4; + msg.writeInt(testInt); + msg.reset(); + assertTrue(((Integer)msg.readObject()).intValue() == testInt); + msg.clearBody(); + + long testLong = 6L; + msg.writeLong(testLong); + msg.reset(); + assertTrue(((Long)msg.readObject()).longValue() == testLong); + msg.clearBody(); + + float testFloat = 6.6f; + msg.writeFloat(testFloat); + msg.reset(); + assertTrue(((Float)msg.readObject()).floatValue() == testFloat); + msg.clearBody(); + + double testDouble = 7.7d; + msg.writeDouble(testDouble); + msg.reset(); + assertTrue(((Double)msg.readObject()).doubleValue() == testDouble); + msg.clearBody(); + + char testChar = 'z'; + msg.writeChar(testChar); + msg.reset(); + assertTrue(((Character)msg.readObject()).charValue() == testChar); + msg.clearBody(); + + byte[] data = new byte[50]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte)i; + } + msg.writeBytes(data); + msg.reset(); + byte[] valid = (byte[])msg.readObject(); + assertTrue(valid.length == data.length); + for (int i = 0; i < valid.length; i++) { + assertTrue(valid[i] == data[i]); + } + msg.clearBody(); + msg.writeBoolean(true); + msg.reset(); + assertTrue(((Boolean)msg.readObject()).booleanValue()); + + } catch (JMSException jmsEx) { + jmsEx.printStackTrace(); + assertTrue(false); + } + } + + public void testClearBody() throws JMSException { + ActiveMQStreamMessage streamMessage = new ActiveMQStreamMessage(); + try { + streamMessage.writeObject(new Long(2)); + streamMessage.clearBody(); + assertFalse(streamMessage.isReadOnlyBody()); + streamMessage.writeObject(new Long(2)); + streamMessage.readObject(); + fail("should throw exception"); + } catch (MessageNotReadableException mnwe) { + } catch (MessageNotWriteableException mnwe) { + fail("should be writeable"); + } + } + + public void testReset() throws JMSException { + ActiveMQStreamMessage streamMessage = new ActiveMQStreamMessage(); + try { + streamMessage.writeDouble(24.5); + streamMessage.writeLong(311); + } catch (MessageNotWriteableException mnwe) { + fail("should be writeable"); + } + streamMessage.reset(); + try { + assertTrue(streamMessage.isReadOnlyBody()); + assertEquals(streamMessage.readDouble(), 24.5, 0); + assertEquals(streamMessage.readLong(), 311); + } catch (MessageNotReadableException mnre) { + fail("should be readable"); + } + try { + streamMessage.writeInt(33); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + } + + public void testReadOnlyBody() throws JMSException { + ActiveMQStreamMessage message = new ActiveMQStreamMessage(); + try { + message.writeBoolean(true); + message.writeByte((byte)1); + message.writeBytes(new byte[1]); + message.writeBytes(new byte[3], 0, 2); + message.writeChar('a'); + message.writeDouble(1.5); + message.writeFloat((float)1.5); + message.writeInt(1); + message.writeLong(1); + message.writeObject("stringobj"); + message.writeShort((short)1); + message.writeString("string"); + } catch (MessageNotWriteableException mnwe) { + fail("Should be writeable"); + } + message.reset(); + try { + message.readBoolean(); + message.readByte(); + assertEquals(1, message.readBytes(new byte[10])); + assertEquals(-1, message.readBytes(new byte[10])); + assertEquals(2, message.readBytes(new byte[10])); + assertEquals(-1, message.readBytes(new byte[10])); + message.readChar(); + message.readDouble(); + message.readFloat(); + message.readInt(); + message.readLong(); + message.readString(); + message.readShort(); + message.readString(); + } catch (MessageNotReadableException mnwe) { + fail("Should be readable"); + } + try { + message.writeBoolean(true); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeByte((byte)1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeBytes(new byte[3], 0, 2); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeChar('a'); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeDouble(1.5); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeFloat((float)1.5); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeInt(1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeLong(1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeObject("stringobj"); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeShort((short)1); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + try { + message.writeString("string"); + fail("Should have thrown exception"); + } catch (MessageNotWriteableException mnwe) { + } + } + + public void testWriteOnlyBody() throws JMSException { + ActiveMQStreamMessage message = new ActiveMQStreamMessage(); + message.clearBody(); + try { + message.writeBoolean(true); + message.writeByte((byte)1); + message.writeBytes(new byte[1]); + message.writeBytes(new byte[3], 0, 2); + message.writeChar('a'); + message.writeDouble(1.5); + message.writeFloat((float)1.5); + message.writeInt(1); + message.writeLong(1); + message.writeObject("stringobj"); + message.writeShort((short)1); + message.writeString("string"); + } catch (MessageNotWriteableException mnwe) { + fail("Should be writeable"); + } + try { + message.readBoolean(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException mnwe) { + } + try { + message.readByte(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readBytes(new byte[1]); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readBytes(new byte[2]); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readChar(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readDouble(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readFloat(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readInt(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readLong(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readString(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readShort(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + try { + message.readString(); + fail("Should have thrown exception"); + } catch (MessageNotReadableException e) { + } + } + + public void testWriteObject() { + try { + ActiveMQStreamMessage message = new ActiveMQStreamMessage(); + message.clearBody(); + message.writeObject("test"); + message.writeObject(new Character('a')); + message.writeObject(new Boolean(false)); + message.writeObject(new Byte((byte) 2)); + message.writeObject(new Short((short) 2)); + message.writeObject(new Integer(2)); + message.writeObject(new Long(2l)); + message.writeObject(new Float(2.0f)); + message.writeObject(new Double(2.0d)); + }catch(Exception e) { + fail(e.getMessage()); + } + try { + ActiveMQStreamMessage message = new ActiveMQStreamMessage(); + message.clearBody(); + message.writeObject(new Object()); + fail("should throw an exception"); + }catch(MessageFormatException e) { + + }catch(Exception e) { + fail(e.getMessage()); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQTextMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQTextMessageTest.java new file mode 100644 index 0000000000..28fc307c5e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/ActiveMQTextMessageTest.java @@ -0,0 +1,159 @@ +/** + * 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.command; + +import java.io.DataOutputStream; +import java.io.IOException; + +import javax.jms.JMSException; +import javax.jms.MessageNotReadableException; +import javax.jms.MessageNotWriteableException; + +import junit.framework.TestCase; +import junit.textui.TestRunner; + +import org.apache.activemq.util.ByteArrayOutputStream; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.util.MarshallingSupport; + +/** + * + */ +public class ActiveMQTextMessageTest extends TestCase { + + public static void main(String[] args) { + TestRunner.run(ActiveMQTextMessageTest.class); + } + + public void testGetDataStructureType() { + ActiveMQTextMessage msg = new ActiveMQTextMessage(); + assertEquals(msg.getDataStructureType(), CommandTypes.ACTIVEMQ_TEXT_MESSAGE); + } + + public void testShallowCopy() throws JMSException { + ActiveMQTextMessage msg = new ActiveMQTextMessage(); + String string = "str"; + msg.setText(string); + Message copy = msg.copy(); + assertTrue(msg.getText() == ((ActiveMQTextMessage) copy).getText()); + } + + public void testSetText() { + ActiveMQTextMessage msg = new ActiveMQTextMessage(); + String str = "testText"; + try { + msg.setText(str); + assertEquals(msg.getText(), str); + } catch (JMSException e) { + e.printStackTrace(); + } + } + + public void testGetBytes() throws JMSException, IOException { + ActiveMQTextMessage msg = new ActiveMQTextMessage(); + String str = "testText"; + msg.setText(str); + msg.beforeMarshall(null); + + ByteSequence bytes = msg.getContent(); + msg = new ActiveMQTextMessage(); + msg.setContent(bytes); + + assertEquals(msg.getText(), str); + } + + public void testClearBody() throws JMSException, IOException { + ActiveMQTextMessage textMessage = new ActiveMQTextMessage(); + textMessage.setText("string"); + textMessage.clearBody(); + assertFalse(textMessage.isReadOnlyBody()); + assertNull(textMessage.getText()); + try { + textMessage.setText("String"); + textMessage.getText(); + } catch (MessageNotWriteableException mnwe) { + fail("should be writeable"); + } catch (MessageNotReadableException mnre) { + fail("should be readable"); + } + } + + public void testReadOnlyBody() throws JMSException { + ActiveMQTextMessage textMessage = new ActiveMQTextMessage(); + textMessage.setText("test"); + textMessage.setReadOnlyBody(true); + try { + textMessage.getText(); + } catch (MessageNotReadableException e) { + fail("should be readable"); + } + try { + textMessage.setText("test"); + fail("should throw exception"); + } catch (MessageNotWriteableException mnwe) { + } + } + + public void testWriteOnlyBody() throws JMSException { // should always be readable + ActiveMQTextMessage textMessage = new ActiveMQTextMessage(); + textMessage.setReadOnlyBody(false); + try { + textMessage.setText("test"); + textMessage.getText(); + } catch (MessageNotReadableException e) { + fail("should be readable"); + } + textMessage.setReadOnlyBody(true); + try { + textMessage.getText(); + textMessage.setText("test"); + fail("should throw exception"); + } catch (MessageNotReadableException e) { + fail("should be readable"); + } catch (MessageNotWriteableException mnwe) { + } + } + + public void testShortText() throws Exception { + String shortText = "Content"; + ActiveMQTextMessage shortMessage = new ActiveMQTextMessage(); + setContent(shortMessage, shortText); + assertTrue(shortMessage.toString().contains("text = " + shortText)); + assertTrue(shortMessage.getText().equals(shortText)); + + String longText = "Very very very very veeeeeeery loooooooooooooooooooooooooooooooooong text"; + String longExpectedText = "Very very very very veeeeeeery looooooooooooo...ooooong text"; + ActiveMQTextMessage longMessage = new ActiveMQTextMessage(); + setContent(longMessage, longText); + assertTrue(longMessage.toString().contains("text = " + longExpectedText)); + assertTrue(longMessage.getText().equals(longText)); + } + + public void testNullText() throws Exception { + ActiveMQTextMessage nullMessage = new ActiveMQTextMessage(); + setContent(nullMessage, null); + assertTrue(nullMessage.toString().contains("text = null")); + } + + protected void setContent(Message message, String text) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(baos); + MarshallingSupport.writeUTF8(dataOut, text); + dataOut.close(); + message.setContent(baos.toByteSequence()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/DataStructureTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/DataStructureTestSupport.java new file mode 100644 index 0000000000..fa977af07e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/DataStructureTestSupport.java @@ -0,0 +1,158 @@ +/** + * 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.command; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.wireformat.WireFormat; + +public abstract class DataStructureTestSupport extends CombinationTestSupport { + public boolean cacheEnabled; + public WireFormat wireFormat; + + public void assertBeanMarshalls(Object original) throws IOException { + Object o = marshalAndUnmarshall(original, wireFormat); + assertNotNull(o); + assertEquals(original, o); + // assertEquals(original.getClass(), o.getClass()); + // + // Method[] methods = original.getClass().getMethods(); + // for (int i = 0; i < methods.length; i++) { + // Method method = methods[i]; + // if( ( method.getName().startsWith("get") + // || method.getName().startsWith("is") + // ) + // && method.getParameterTypes().length==0 + // && method.getReturnType()!=null + // ) { + // try { + // Object expect = method.invoke(original, null); + // Object was = method.invoke(o, null); + // assertEquals(expect, was); + // } catch (IllegalArgumentException e) { + // } catch (IllegalAccessException e) { + // } catch (InvocationTargetException e) { + // } + // } + // } + } + + public static void assertEquals(Object expect, Object was) { + if (expect == null ^ was == null) { + throw new AssertionFailedError("Not equals, expected: " + expect + ", was: " + was); + } + if (expect == null) { + return; + } + if (expect.getClass() != was.getClass()) { + throw new AssertionFailedError("Not equals, classes don't match. expected: " + expect.getClass() + ", was: " + was.getClass()); + } + if (expect.getClass().isArray()) { + Class componentType = expect.getClass().getComponentType(); + if (componentType.isPrimitive()) { + boolean ok = false; + if (componentType == byte.class) { + ok = Arrays.equals((byte[])expect, (byte[])was); + } + if (componentType == char.class) { + ok = Arrays.equals((char[])expect, (char[])was); + } + if (componentType == short.class) { + ok = Arrays.equals((short[])expect, (short[])was); + } + if (componentType == int.class) { + ok = Arrays.equals((int[])expect, (int[])was); + } + if (componentType == long.class) { + ok = Arrays.equals((long[])expect, (long[])was); + } + if (componentType == double.class) { + ok = Arrays.equals((double[])expect, (double[])was); + } + if (componentType == float.class) { + ok = Arrays.equals((float[])expect, (float[])was); + } + if (!ok) { + throw new AssertionFailedError("Arrays not equal"); + } + } else { + Object expectArray[] = (Object[])expect; + Object wasArray[] = (Object[])was; + if (expectArray.length != wasArray.length) { + throw new AssertionFailedError("Not equals, array lengths don't match. expected: " + expectArray.length + ", was: " + wasArray.length); + } + for (int i = 0; i < wasArray.length; i++) { + assertEquals(expectArray[i], wasArray[i]); + } + + } + } else if (expect instanceof Command) { + assertEquals(expect.getClass(), was.getClass()); + Method[] methods = expect.getClass().getMethods(); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if ((method.getName().startsWith("get") || method.getName().startsWith("is")) && method.getParameterTypes().length == 0 && method.getReturnType() != null) { + + // Check to see if there is a setter for the method. + try { + if (method.getName().startsWith("get")) { + expect.getClass().getMethod(method.getName().replaceFirst("get", "set"), new Class[] {method.getReturnType()}); + } else { + expect.getClass().getMethod(method.getName().replaceFirst("is", "set"), new Class[] {method.getReturnType()}); + } + } catch (Throwable ignore) { + continue; + } + + try { + assertEquals(method.invoke(expect, (Object)null), method.invoke(was, (Object)null)); + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } catch (InvocationTargetException e) { + } + } + } + } else { + TestCase.assertEquals(expect, was); + } + } + + protected void setUp() throws Exception { + wireFormat = createWireFormat(); + super.setUp(); + } + + protected WireFormat createWireFormat() { + OpenWireFormat answer = new OpenWireFormat(); + answer.setCacheEnabled(cacheEnabled); + return answer; + } + + protected Object marshalAndUnmarshall(Object original, WireFormat wireFormat) throws IOException { + ByteSequence packet = wireFormat.marshal(original); + return wireFormat.unmarshal(packet); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageCompressionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageCompressionTest.java new file mode 100644 index 0000000000..4c77bfcdea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageCompressionTest.java @@ -0,0 +1,143 @@ +/** + * 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.command; + +import java.io.UnsupportedEncodingException; + +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; + +public class MessageCompressionTest extends TestCase { + + private static final String BROKER_URL = "tcp://localhost:0"; + // The following text should compress well + private static final String TEXT = "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. " + + "The quick red fox jumped over the lazy brown dog. " + "The quick red fox jumped over the lazy brown dog. "; + + private BrokerService broker; + private ActiveMQQueue queue; + private String connectionUri; + + protected void setUp() throws Exception { + broker = new BrokerService(); + connectionUri = broker.addConnector(BROKER_URL).getPublishableConnectString(); + broker.start(); + queue = new ActiveMQQueue("TEST." + System.currentTimeMillis()); + } + + protected void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + public void testTextMessageCompression() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + factory.setUseCompression(true); + sendTestMessage(factory, TEXT); + ActiveMQTextMessage message = receiveTestMessage(factory); + int compressedSize = message.getContent().getLength(); + + factory = new ActiveMQConnectionFactory(connectionUri); + factory.setUseCompression(false); + sendTestMessage(factory, TEXT); + message = receiveTestMessage(factory); + int unCompressedSize = message.getContent().getLength(); + + assertTrue("expected: compressed Size '" + compressedSize + "' < unCompressedSize '" + unCompressedSize + "'", + compressedSize < unCompressedSize); + } + + public void testBytesMessageCompression() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + factory.setUseCompression(true); + sendTestBytesMessage(factory, TEXT); + ActiveMQBytesMessage message = receiveTestBytesMessage(factory); + int compressedSize = message.getContent().getLength(); + byte[] bytes = new byte[TEXT.getBytes("UTF8").length]; + message.readBytes(bytes); + assertTrue(message.readBytes(new byte[255]) == -1); + String rcvString = new String(bytes, "UTF8"); + assertEquals(TEXT, rcvString); + assertTrue(message.isCompressed()); + + factory = new ActiveMQConnectionFactory(connectionUri); + factory.setUseCompression(false); + sendTestBytesMessage(factory, TEXT); + message = receiveTestBytesMessage(factory); + int unCompressedSize = message.getContent().getLength(); + + assertTrue("expected: compressed Size '" + compressedSize + "' < unCompressedSize '" + unCompressedSize + "'", + compressedSize < unCompressedSize); + } + + private void sendTestMessage(ActiveMQConnectionFactory factory, String message) throws JMSException { + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + producer.send(session.createTextMessage(message)); + connection.close(); + } + + private ActiveMQTextMessage receiveTestMessage(ActiveMQConnectionFactory factory) throws JMSException { + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + ActiveMQTextMessage rc = (ActiveMQTextMessage) consumer.receive(); + connection.close(); + return rc; + } + + private void sendTestBytesMessage(ActiveMQConnectionFactory factory, String message) throws JMSException, UnsupportedEncodingException { + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + BytesMessage bytesMessage = session.createBytesMessage(); + bytesMessage.writeBytes(message.getBytes("UTF8")); + producer.send(bytesMessage); + connection.close(); + } + + private ActiveMQBytesMessage receiveTestBytesMessage(ActiveMQConnectionFactory factory) throws JMSException, UnsupportedEncodingException { + ActiveMQConnection connection = (ActiveMQConnection) factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + ActiveMQBytesMessage rc = (ActiveMQBytesMessage) consumer.receive(); + connection.close(); + return rc; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageSendTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageSendTest.java new file mode 100644 index 0000000000..ec81800d0a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageSendTest.java @@ -0,0 +1,78 @@ +/** + * 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.command; + +import java.io.IOException; + +import junit.framework.Test; + +import org.apache.activemq.util.ByteSequence; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageSendTest extends DataStructureTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(MessageSendTest.class); + + public static Test suite() { + return suite(MessageSendTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void initCombosForTestMessageSendMarshaling() { + addCombinationValues("cacheEnabled", new Object[] {Boolean.TRUE, Boolean.FALSE}); + } + + public void testMessageSendMarshaling() throws IOException { + ActiveMQMessage message = new ActiveMQMessage(); + message.setCommandId((short)1); + message.setDestination(new ActiveMQQueue("queue")); + message.setGroupID("group"); + message.setGroupSequence(4); + message.setCorrelationId("correlation"); + message.setMessageId(new MessageId("c1:1:1", 1)); + + assertBeanMarshalls(message); + assertBeanMarshalls(message); + + } + + public void xtestPerformance() throws IOException { + ActiveMQMessage message = new ActiveMQMessage(); + message.setProducerId(new ProducerId(new SessionId(new ConnectionId(new ConnectionId("test")), 1), 1)); + message.setMessageId(new MessageId(message.getProducerId(), 1)); + message.setCommandId((short)1); + message.setGroupID("group"); + message.setGroupSequence(4); + message.setCorrelationId("correlation"); + message.setContent(new ByteSequence(new byte[1024], 0, 1024)); + message.setTimestamp(System.currentTimeMillis()); + message.setDestination(new ActiveMQQueue("TEST")); + + int p = 1000000; + + long start = System.currentTimeMillis(); + for (int i = 0; i < p; i++) { + marshalAndUnmarshall(message, wireFormat); + } + long end = System.currentTimeMillis(); + + LOG.info("marshaled/unmarshaled: " + p + " msgs at " + (p * 1000f / (end - start)) + " msgs/sec"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageTest.java new file mode 100644 index 0000000000..f33c5b4524 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/command/MessageTest.java @@ -0,0 +1,100 @@ +/** + * 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.command; + +import java.io.IOException; + +import junit.framework.Test; +import junit.textui.TestRunner; + +public class MessageTest extends DataStructureTestSupport { + + public boolean cacheEnabled; + + public static Test suite() { + return suite(MessageTest.class); + } + + public static void main(String[] args) { + TestRunner.run(suite()); + } + + public void initCombosForTestActiveMQMessageMarshaling() { + addCombinationValues("cacheEnabled", new Object[] {Boolean.TRUE, Boolean.FALSE}); + } + + public void testActiveMQMessageMarshaling() throws IOException { + ActiveMQMessage message = new ActiveMQMessage(); + message.setCommandId((short)1); + message.setOriginalDestination(new ActiveMQQueue("queue")); + message.setGroupID("group"); + message.setGroupSequence(4); + message.setCorrelationId("correlation"); + message.setMessageId(new MessageId("c1:1:1", 1)); + assertBeanMarshalls(message); + } + + public void testActiveMQMessageMarshalingBigMessageId() throws IOException { + ActiveMQMessage message = new ActiveMQMessage(); + message.setCommandId((short)1); + message.setOriginalDestination(new ActiveMQQueue("queue")); + message.setGroupID("group"); + message.setGroupSequence(4); + message.setCorrelationId("correlation"); + message.setMessageId(new MessageId("c1:1:1", Short.MAX_VALUE)); + assertBeanMarshalls(message); + } + + public void testActiveMQMessageMarshalingBiggerMessageId() throws IOException { + ActiveMQMessage message = new ActiveMQMessage(); + message.setCommandId((short)1); + message.setOriginalDestination(new ActiveMQQueue("queue")); + message.setGroupID("group"); + message.setGroupSequence(4); + message.setCorrelationId("correlation"); + message.setMessageId(new MessageId("c1:1:1", Integer.MAX_VALUE)); + assertBeanMarshalls(message); + } + + public void testActiveMQMessageMarshalingBiggestMessageId() throws IOException { + ActiveMQMessage message = new ActiveMQMessage(); + message.setCommandId((short)1); + message.setOriginalDestination(new ActiveMQQueue("queue")); + message.setGroupID("group"); + message.setGroupSequence(4); + message.setCorrelationId("correlation"); + message.setMessageId(new MessageId("c1:1:1", Long.MAX_VALUE)); + assertBeanMarshalls(message); + } + + public void testMessageIdMarshaling() throws IOException { + assertBeanMarshalls(new MessageId("c1:1:1", 1)); + } + + public void testPropRemove() throws Exception { + ActiveMQMessage message = new ActiveMQMessage(); + message.setStringProperty("RM","RM"); + + ActiveMQMessage unMarshalled = (ActiveMQMessage) marshalAndUnmarshall(message, wireFormat); + + unMarshalled.getBooleanProperty("NA"); + unMarshalled.removeProperty("RM"); + + ActiveMQMessage unMarshalledAgain = (ActiveMQMessage) marshalAndUnmarshall(unMarshalled, wireFormat); + assertNull("Prop is gone", unMarshalledAgain.getProperty("RM")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerPropertiesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerPropertiesTest.java new file mode 100644 index 0000000000..f8c3ec5725 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerPropertiesTest.java @@ -0,0 +1,60 @@ +/** + * 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.config; + +import javax.jms.Connection; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class BrokerPropertiesTest extends TestCase { + private static final transient Logger LOG = LoggerFactory.getLogger(BrokerPropertiesTest.class); + + public void testPropertiesFile() throws Exception { + BrokerService broker = BrokerFactory.createBroker("properties:org/apache/activemq/config/broker.properties"); + + LOG.info("Created broker: " + broker); + assertNotNull(broker); + + assertEquals("isUseJmx()", false, broker.isUseJmx()); + assertEquals("isPersistent()", false, broker.isPersistent()); + assertEquals("getBrokerName()", "Cheese", broker.getBrokerName()); + broker.stop(); + } + + + public void testVmBrokerPropertiesFile() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?brokerConfig=properties:org/apache/activemq/config/broker.properties"); + Connection connection = factory.createConnection(); + BrokerService broker = BrokerRegistry.getInstance().lookup("Cheese"); + LOG.info("Found broker : " + broker); + assertNotNull(broker); + + assertEquals("isUseJmx()", false, broker.isUseJmx()); + assertEquals("isPersistent()", false, broker.isPersistent()); + assertEquals("getBrokerName()", "Cheese", broker.getBrokerName()); + connection.close(); + broker.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerXmlConfigFromJNDITest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerXmlConfigFromJNDITest.java new file mode 100644 index 0000000000..936603c3b8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerXmlConfigFromJNDITest.java @@ -0,0 +1,53 @@ +/** + * 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.config; + +import java.io.File; +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.InitialContext; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; + +/** + * + */ +public class BrokerXmlConfigFromJNDITest extends JmsTopicSendReceiveWithTwoConnectionsTest { + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + assertBaseDirectoryContainsSpaces(); + + // we could put these properties into a jndi.properties + // on the classpath instead + Hashtable properties = new Hashtable(); + properties.put("java.naming.factory.initial", "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + + // configure the embedded broker using an XML config file + // which is either a URL or a resource on the classpath + File f = new File(System.getProperty("basedir", "."), "/src/test/resources/activemq.xml"); + properties.put(Context.PROVIDER_URL, "vm://localhost?brokerConfig=xbean:" + f.toURI()); + + InitialContext context = new InitialContext(properties); + ActiveMQConnectionFactory connectionFactory = (ActiveMQConnectionFactory) context.lookup("ConnectionFactory"); + + // END SNIPPET: example + return connectionFactory; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerXmlConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerXmlConfigTest.java new file mode 100644 index 0000000000..c392b121ed --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/BrokerXmlConfigTest.java @@ -0,0 +1,48 @@ +/** + * 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.config; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; + +/** + * + */ +public class BrokerXmlConfigTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + // START SNIPPET: bean + + // configure the connection factory using + // normal Java Bean property methods + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); + + // configure the embedded broker using an XML config file + // which is either a URL or a resource on the classpath + + // TODO ... + + //connectionFactory.setBrokerXmlConfig("file:src/sample-conf/default.xml"); + + // you only need to configure the broker URL if you wish to change the + // default connection mechanism, which in this test case we do + connectionFactory.setBrokerURL("vm://localhost"); + + // END SNIPPET: bean + return connectionFactory; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/ConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/ConfigTest.java new file mode 100644 index 0000000000..82b5ebec76 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/ConfigTest.java @@ -0,0 +1,457 @@ +/** + * 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.config; + +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 java.io.File; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.util.List; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.sql.DataSource; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.FixedSizedSubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.LastImageSubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.NoSubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.RoundRobinDispatchPolicy; +import org.apache.activemq.broker.region.policy.SimpleDispatchPolicy; +import org.apache.activemq.broker.region.policy.StrictOrderDispatchPolicy; +import org.apache.activemq.broker.region.policy.SubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.TimedSubscriptionRecoveryPolicy; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.DefaultDatabaseLocker; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.store.jdbc.adapter.TransactDatabaseLocker; +import org.apache.activemq.store.journal.JournalPersistenceAdapter; +import org.apache.activemq.store.memory.MemoryPersistenceAdapter; +import org.apache.activemq.transport.tcp.TcpTransportServer; +import org.apache.activemq.usage.SystemUsage; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +public class ConfigTest { + + protected static final String JOURNAL_ROOT = "target/test-data/"; + protected static final String DERBY_ROOT = "target/test-data/"; + protected static final String CONF_ROOT = "src/test/resources/org/apache/activemq/config/sample-conf/"; + private static final Logger LOG = LoggerFactory.getLogger(ConfigTest.class); + + static { + System.setProperty("javax.net.ssl.trustStore", "src/test/resources/client.keystore"); + System.setProperty("javax.net.ssl.trustStorePassword", "password"); + System.setProperty("javax.net.ssl.trustStoreType", "jks"); + System.setProperty("javax.net.ssl.keyStore", "src/test/resources/server.keystore"); + System.setProperty("javax.net.ssl.keyStorePassword", "password"); + System.setProperty("javax.net.ssl.keyStoreType", "jks"); + } + + /* + * IMPORTANT NOTE: Assertions checking for the existence of the derby + * directory will fail if the first derby directory is not created under + * target/test-data/. The test in unable to change the derby root directory + * for succeeding creation. It uses the first created directory as the root. + */ + + /* + * This tests creating a journal persistence adapter using the persistence + * adapter factory bean + */ + @Test + public void testJournaledJDBCConfig() throws Exception { + + File journalFile = new File(JOURNAL_ROOT + "testJournaledJDBCConfig/journal"); + recursiveDelete(journalFile); + + File derbyFile = new File(DERBY_ROOT + "testJournaledJDBCConfig/derbydb"); // Default + recursiveDelete(derbyFile); + + BrokerService broker; + broker = createBroker(new FileSystemResource(CONF_ROOT + "journaledjdbc-example.xml")); + try { + assertEquals("Broker Config Error (brokerName)", "brokerJournaledJDBCConfigTest", broker.getBrokerName()); + + PersistenceAdapter adapter = broker.getPersistenceAdapter(); + + assertTrue("Should have created a journal persistence adapter", adapter instanceof JournalPersistenceAdapter); + assertTrue("Should have created a derby directory at " + derbyFile.getAbsolutePath(), derbyFile.exists()); + assertTrue("Should have created a journal directory at " + journalFile.getAbsolutePath(), journalFile.exists()); + + // Check persistence factory configurations + broker.getPersistenceAdapter(); + + assertTrue(broker.getSystemUsage().getStoreUsage().getStore() instanceof JournalPersistenceAdapter); + + LOG.info("Success"); + } finally { + if (broker != null) { + broker.stop(); + } + } + } + + @Test + public void testJdbcLockConfigOverride() throws Exception { + + JDBCPersistenceAdapter adapter = new JDBCPersistenceAdapter(); + Mockery context = new Mockery(); + final DataSource dataSource = context.mock(DataSource.class); + final Connection connection = context.mock(Connection.class); + final DatabaseMetaData metadata = context.mock(DatabaseMetaData.class); + final ResultSet result = context.mock(ResultSet.class); + adapter.setDataSource(dataSource); + adapter.setCreateTablesOnStartup(false); + + context.checking(new Expectations() {{ + allowing(dataSource).getConnection(); + will(returnValue(connection)); + allowing(connection).getMetaData(); + will(returnValue(metadata)); + allowing(connection); + allowing(metadata).getDriverName(); + will(returnValue("Microsoft_SQL_Server_2005_jdbc_driver")); + allowing(result).next(); + will(returnValue(true)); + }}); + + adapter.start(); + assertTrue("has the locker override", adapter.getLocker() instanceof TransactDatabaseLocker); + adapter.stop(); + } + + public void testJdbcLockConfigDefault() throws Exception { + + JDBCPersistenceAdapter adapter = new JDBCPersistenceAdapter(); + Mockery context = new Mockery(); + final DataSource dataSource = context.mock(DataSource.class); + final Connection connection = context.mock(Connection.class); + final DatabaseMetaData metadata = context.mock(DatabaseMetaData.class); + final ResultSet result = context.mock(ResultSet.class); + adapter.setDataSource(dataSource); + adapter.setCreateTablesOnStartup(false); + + context.checking(new Expectations() {{ + allowing(dataSource).getConnection(); + will(returnValue(connection)); + allowing(connection).getMetaData(); + will(returnValue(metadata)); + allowing(connection); + allowing(metadata).getDriverName(); + will(returnValue("Some_Unknown_driver")); + allowing(result).next(); + will(returnValue(true)); + }}); + + adapter.start(); + assertEquals("has the default locker", adapter.getLocker().getClass(), DefaultDatabaseLocker.class); + adapter.stop(); + } + + /* + * This tests configuring the different broker properties using + * xbeans-spring + */ + @Test + public void testBrokerConfig() throws Exception { + ActiveMQTopic dest; + BrokerService broker; + + File journalFile = new File(JOURNAL_ROOT); + recursiveDelete(journalFile); + + // Create broker from resource + // System.out.print("Creating broker... "); + broker = createBroker("org/apache/activemq/config/example.xml"); + LOG.info("Success"); + + try { + // Check broker configuration + // System.out.print("Checking broker configurations... "); + assertEquals("Broker Config Error (brokerName)", "brokerConfigTest", broker.getBrokerName()); + assertEquals("Broker Config Error (populateJMSXUserID)", false, broker.isPopulateJMSXUserID()); + assertEquals("Broker Config Error (useLoggingForShutdownErrors)", true, broker.isUseLoggingForShutdownErrors()); + assertEquals("Broker Config Error (useJmx)", true, broker.isUseJmx()); + assertEquals("Broker Config Error (persistent)", false, broker.isPersistent()); + assertEquals("Broker Config Error (useShutdownHook)", false, broker.isUseShutdownHook()); + assertEquals("Broker Config Error (deleteAllMessagesOnStartup)", true, broker.isDeleteAllMessagesOnStartup()); + LOG.info("Success"); + + // Check specific vm transport + // System.out.print("Checking vm connector... "); + assertEquals("Should have a specific VM Connector", "vm://javacoola", broker.getVmConnectorURI().toString()); + LOG.info("Success"); + + // Check transport connectors list + // System.out.print("Checking transport connectors... "); + List connectors = broker.getTransportConnectors(); + assertTrue("Should have created at least 3 connectors", connectors.size() >= 3); + assertTrue("1st connector should be TcpTransportServer", connectors.get(0).getServer() instanceof TcpTransportServer); + assertTrue("2nd connector should be TcpTransportServer", connectors.get(1).getServer() instanceof TcpTransportServer); + assertTrue("3rd connector should be TcpTransportServer", connectors.get(2).getServer() instanceof TcpTransportServer); + + // Check network connectors + // System.out.print("Checking network connectors... "); + List networkConnectors = broker.getNetworkConnectors(); + assertEquals("Should have a single network connector", 1, networkConnectors.size()); + LOG.info("Success"); + + // Check dispatch policy configuration + // System.out.print("Checking dispatch policies... "); + + dest = new ActiveMQTopic("Topic.SimpleDispatch"); + assertTrue("Should have a simple dispatch policy for " + dest.getTopicName(), + broker.getDestinationPolicy().getEntryFor(dest).getDispatchPolicy() instanceof SimpleDispatchPolicy); + + dest = new ActiveMQTopic("Topic.RoundRobinDispatch"); + assertTrue("Should have a round robin dispatch policy for " + dest.getTopicName(), + broker.getDestinationPolicy().getEntryFor(dest).getDispatchPolicy() instanceof RoundRobinDispatchPolicy); + + dest = new ActiveMQTopic("Topic.StrictOrderDispatch"); + assertTrue("Should have a strict order dispatch policy for " + dest.getTopicName(), + broker.getDestinationPolicy().getEntryFor(dest).getDispatchPolicy() instanceof StrictOrderDispatchPolicy); + LOG.info("Success"); + + // Check subscription policy configuration + // System.out.print("Checking subscription recovery policies... "); + SubscriptionRecoveryPolicy subsPolicy; + + dest = new ActiveMQTopic("Topic.FixedSizedSubs"); + subsPolicy = broker.getDestinationPolicy().getEntryFor(dest).getSubscriptionRecoveryPolicy(); + assertTrue("Should have a fixed sized subscription recovery policy for " + dest.getTopicName(), subsPolicy instanceof FixedSizedSubscriptionRecoveryPolicy); + assertEquals("FixedSizedSubsPolicy Config Error (maximumSize)", 2000000, ((FixedSizedSubscriptionRecoveryPolicy) subsPolicy).getMaximumSize()); + assertEquals("FixedSizedSubsPolicy Config Error (useSharedBuffer)", false, ((FixedSizedSubscriptionRecoveryPolicy) subsPolicy).isUseSharedBuffer()); + + dest = new ActiveMQTopic("Topic.LastImageSubs"); + subsPolicy = broker.getDestinationPolicy().getEntryFor(dest).getSubscriptionRecoveryPolicy(); + assertTrue("Should have a last image subscription recovery policy for " + dest.getTopicName(), subsPolicy instanceof LastImageSubscriptionRecoveryPolicy); + + dest = new ActiveMQTopic("Topic.NoSubs"); + subsPolicy = broker.getDestinationPolicy().getEntryFor(dest).getSubscriptionRecoveryPolicy(); + assertTrue("Should have no subscription recovery policy for " + dest.getTopicName(), subsPolicy instanceof NoSubscriptionRecoveryPolicy); + + dest = new ActiveMQTopic("Topic.TimedSubs"); + subsPolicy = broker.getDestinationPolicy().getEntryFor(dest).getSubscriptionRecoveryPolicy(); + assertTrue("Should have a timed subscription recovery policy for " + dest.getTopicName(), subsPolicy instanceof TimedSubscriptionRecoveryPolicy); + assertEquals("TimedSubsPolicy Config Error (recoverDuration)", 25000, ((TimedSubscriptionRecoveryPolicy) subsPolicy).getRecoverDuration()); + LOG.info("Success"); + + // Check usage manager + // System.out.print("Checking memory manager configurations... "); + SystemUsage systemUsage = broker.getSystemUsage(); + assertTrue("Should have a SystemUsage", systemUsage != null); + assertEquals("SystemUsage Config Error (MemoryUsage.limit)", 1024 * 1024 * 10, systemUsage.getMemoryUsage().getLimit()); + assertEquals("SystemUsage Config Error (MemoryUsage.percentUsageMinDelta)", 20, systemUsage.getMemoryUsage().getPercentUsageMinDelta()); + assertEquals("SystemUsage Config Error (TempUsage.limit)", 1024 * 1024 * 100, systemUsage.getTempUsage().getLimit()); + assertEquals("SystemUsage Config Error (StoreUsage.limit)", 1024 * 1024 * 1024, systemUsage.getStoreUsage().getLimit()); + assertEquals("SystemUsage Config Error (StoreUsage.name)", "foo", systemUsage.getStoreUsage().getName()); + + assertNotNull(systemUsage.getStoreUsage().getStore()); + assertTrue(systemUsage.getStoreUsage().getStore() instanceof MemoryPersistenceAdapter); + + LOG.info("Success"); + + } finally { + if (broker != null) { + broker.stop(); + } + } + } + + /* + * This tests creating a journal persistence adapter using xbeans-spring + */ + @Test + public void testJournalConfig() throws Exception { + File journalFile = new File(JOURNAL_ROOT + "testJournalConfig/journal"); + recursiveDelete(journalFile); + + BrokerService broker; + broker = createBroker(new FileSystemResource(CONF_ROOT + "journal-example.xml")); + try { + assertEquals("Broker Config Error (brokerName)", "brokerJournalConfigTest", broker.getBrokerName()); + + PersistenceAdapter adapter = broker.getPersistenceAdapter(); + + assertTrue("Should have created a journal persistence adapter", adapter instanceof JournalPersistenceAdapter); + assertTrue("Should have created a journal directory at " + journalFile.getAbsolutePath(), journalFile.exists()); + + LOG.info("Success"); + } finally { + if (broker != null) { + broker.stop(); + } + } + } + + /* + * This tests creating a memory persistence adapter using xbeans-spring + */ + @Test + public void testMemoryConfig() throws Exception { + File journalFile = new File(JOURNAL_ROOT + "testMemoryConfig"); + recursiveDelete(journalFile); + + File derbyFile = new File(DERBY_ROOT + "testMemoryConfig"); + recursiveDelete(derbyFile); + + BrokerService broker; + broker = createBroker(new FileSystemResource(CONF_ROOT + "memory-example.xml")); + + try { + assertEquals("Broker Config Error (brokerName)", "brokerMemoryConfigTest", broker.getBrokerName()); + + PersistenceAdapter adapter = broker.getPersistenceAdapter(); + + assertTrue("Should have created a memory persistence adapter", adapter instanceof MemoryPersistenceAdapter); + assertTrue("Should have not created a derby directory at " + derbyFile.getAbsolutePath(), !derbyFile.exists()); + assertTrue("Should have not created a journal directory at " + journalFile.getAbsolutePath(), !journalFile.exists()); + + LOG.info("Success"); + } finally { + if (broker != null) { + broker.stop(); + } + } + } + + @Test + public void testConnectorConfig() throws Exception { + + File journalFile = new File(JOURNAL_ROOT + "testMemoryConfig"); + recursiveDelete(journalFile); + + File derbyFile = new File(DERBY_ROOT + "testMemoryConfig"); + recursiveDelete(derbyFile); + + final int MAX_PRODUCERS = 5; + final int MAX_CONSUMERS = 10; + + BrokerService broker = createBroker(new FileSystemResource(CONF_ROOT + "connector-properties.xml")); + broker.start(); + try { + + assertEquals(broker.getTransportConnectorByScheme("tcp").getMaximumProducersAllowedPerConnection(), MAX_PRODUCERS); + assertEquals(broker.getTransportConnectorByScheme("tcp").getMaximumConsumersAllowedPerConnection(), MAX_CONSUMERS); + + ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61631"); + javax.jms.Connection connection = activeMQConnectionFactory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("test.foo"); + + for (int i = 0; i < MAX_PRODUCERS; i++) { + session.createProducer(topic); + } + + try { + session.createProducer(topic); + fail("Should have got an exception on exceeding MAX_PRODUCERS"); + } catch (JMSException expected) { + } + + try { + for (int i = 0; i < (MAX_CONSUMERS + 1); i++) { + MessageConsumer consumer = session.createConsumer(topic); + assertNotNull(consumer); + } + fail("Should have caught an exception"); + } catch (JMSException e) { + } + + LOG.info("Success"); + } finally { + if (broker != null) { + broker.stop(); + } + } + } + + @Test + public void testXmlConfigHelper() throws Exception { + BrokerService broker; + + broker = createBroker(new FileSystemResource(CONF_ROOT + "memory-example.xml")); + try { + assertEquals("Broker Config Error (brokerName)", "brokerMemoryConfigTest", broker.getBrokerName()); + } finally { + if (broker != null) { + broker.stop(); + } + } + + broker = createBroker("org/apache/activemq/config/config.xml"); + try { + assertEquals("Broker Config Error (brokerName)", "brokerXmlConfigHelper", broker.getBrokerName()); + } finally { + if (broker != null) { + broker.stop(); + } + } + } + + /* + * TODO: Create additional tests for forwarding bridges + */ + + protected static void recursiveDelete(File file) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + recursiveDelete(files[i]); + } + } + file.delete(); + } + + protected BrokerService createBroker(String resource) throws Exception { + return createBroker(new ClassPathResource(resource)); + } + + protected BrokerService createBroker(Resource resource) throws Exception { + BrokerFactoryBean factory = new BrokerFactoryBean(resource); + factory.afterPropertiesSet(); + + BrokerService broker = factory.getBroker(); + + assertTrue("Should have a broker!", broker != null); + + // Broker is already started by default when using the XML file + // broker.start(); + + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/ConfigUsingDestinationOptions.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/ConfigUsingDestinationOptions.java new file mode 100644 index 0000000000..704e40852a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/ConfigUsingDestinationOptions.java @@ -0,0 +1,72 @@ +/** + * 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.config; + +import javax.jms.Connection; +import javax.jms.InvalidSelectorException; +import javax.jms.JMSException; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQMessageConsumer; +import org.apache.activemq.command.ActiveMQQueue; + +public class ConfigUsingDestinationOptions extends TestCase { + public void testValidSelectorConfig() throws JMSException { + ActiveMQQueue queue = new ActiveMQQueue("TEST.FOO?consumer.selector=test=1"); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createConnection(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQMessageConsumer cons; + // JMS selector should be priority + cons = (ActiveMQMessageConsumer) sess.createConsumer(queue, "test=2"); + assertEquals("test=2", cons.getMessageSelector()); + + // Test setting using JMS destinations + cons = (ActiveMQMessageConsumer) sess.createConsumer(queue); + assertEquals("test=1", cons.getMessageSelector()); + } + + public void testInvalidSelectorConfig() throws JMSException { + ActiveMQQueue queue = new ActiveMQQueue("TEST.FOO?consumer.selector=test||1"); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createConnection(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQMessageConsumer cons; + // JMS selector should be priority + try { + cons = (ActiveMQMessageConsumer) sess.createConsumer(queue, "test||1"); + fail("Selector should be invalid" + cons); + } catch (InvalidSelectorException e) { + + } + + // Test setting using JMS destinations + try { + cons = (ActiveMQMessageConsumer) sess.createConsumer(queue); + fail("Selector should be invalid" + cons); + } catch (InvalidSelectorException e) { + + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/JDBCConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/JDBCConfigTest.java new file mode 100644 index 0000000000..e13f53d7f2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/JDBCConfigTest.java @@ -0,0 +1,102 @@ +/** + * 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.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.activemq.wireformat.ObjectStreamWireFormat; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +public class JDBCConfigTest { + + protected static final String JOURNAL_ROOT = "target/test-data/"; + protected static final String DERBY_ROOT = "target/test-data/"; + protected static final String CONF_ROOT = "src/test/resources/org/apache/activemq/config/sample-conf/"; + private static final Logger LOG = LoggerFactory.getLogger(JDBCConfigTest.class); + + /* + * This tests creating a jdbc persistence adapter using xbeans-spring + */ + @Test + public void testJdbcConfig() throws Exception { + File journalFile = new File(JOURNAL_ROOT + "testJDBCConfig/journal"); + recursiveDelete(journalFile); + + File derbyFile = new File(DERBY_ROOT + "testJDBCConfig/derbydb"); // Default + recursiveDelete(derbyFile); + + BrokerService broker; + broker = createBroker(new FileSystemResource(CONF_ROOT + "jdbc-example.xml")); + try { + assertEquals("Broker Config Error (brokerName)", "brokerJdbcConfigTest", broker.getBrokerName()); + + PersistenceAdapter adapter = broker.getPersistenceAdapter(); + + assertTrue("Should have created a jdbc persistence adapter", adapter instanceof JDBCPersistenceAdapter); + assertEquals("JDBC Adapter Config Error (cleanupPeriod)", 60000, ((JDBCPersistenceAdapter) adapter).getCleanupPeriod()); + assertTrue("Should have created an EmbeddedDataSource", ((JDBCPersistenceAdapter) adapter).getDataSource() instanceof EmbeddedDataSource); + assertTrue("Should have created a DefaultWireFormat", ((JDBCPersistenceAdapter) adapter).getWireFormat() instanceof ObjectStreamWireFormat); + + LOG.info("Success"); + } finally { + if (broker != null) { + broker.stop(); + } + } + } + + protected static void recursiveDelete(File file) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + recursiveDelete(files[i]); + } + } + file.delete(); + } + + protected BrokerService createBroker(String resource) throws Exception { + return createBroker(new ClassPathResource(resource)); + } + + protected BrokerService createBroker(Resource resource) throws Exception { + BrokerFactoryBean factory = new BrokerFactoryBean(resource); + factory.afterPropertiesSet(); + + BrokerService broker = factory.getBroker(); + + assertTrue("Should have a broker!", broker != null); + + // Broker is already started by default when using the XML file + // broker.start(); + + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/broker.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/broker.properties new file mode 100644 index 0000000000..921671f2a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/broker.properties @@ -0,0 +1,21 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- +# START SNIPPET: example +useJmx = false +persistent = false +brokerName = Cheese +# END SNIPPET: example \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/config.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/config.xml new file mode 100644 index 0000000000..9ec13ffbf4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/config.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/example.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/example.xml new file mode 100644 index 0000000000..0a7a686435 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/example.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/connector-properties.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/connector-properties.xml new file mode 100644 index 0000000000..23f065d5c1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/connector-properties.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/jdbc-example.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/jdbc-example.xml new file mode 100644 index 0000000000..bbd98ea842 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/jdbc-example.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/journal-example.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/journal-example.xml new file mode 100644 index 0000000000..2a79308dcf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/journal-example.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + target/test-data/testJournalConfig/journal + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/journaledjdbc-example.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/journaledjdbc-example.xml new file mode 100644 index 0000000000..4a6a0db90c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/journaledjdbc-example.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/memory-example.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/memory-example.xml new file mode 100644 index 0000000000..10b38a8f8b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/sample-conf/memory-example.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/spring-test.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/spring-test.xml new file mode 100644 index 0000000000..0e2f1456f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/config/spring-test.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + vm://localhost + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/AMQ3410Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/AMQ3410Test.java new file mode 100644 index 0000000000..dadff34c8e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/AMQ3410Test.java @@ -0,0 +1,186 @@ +/** + * 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.console.command; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.console.CommandContext; +import org.apache.activemq.console.formatter.CommandShellOutputFormatter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class AMQ3410Test extends TestCase { + @SuppressWarnings("unused") + private static final Logger LOG = LoggerFactory + .getLogger(PurgeCommandTest.class); + private static final Collection DEFAULT_OPTIONS = Arrays + .asList(new String[] { "--amqurl", "tcp://localhost:61616", }); + + private static final Collection DEFAULT_TOKENS = Arrays + .asList(new String[] { "FOO.QUEUE" }); + + protected AbstractApplicationContext context; + + protected void setUp() throws Exception { + super.setUp(); + + context = createApplicationContext(); + + } + + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/console/command/activemq.xml"); + } + + protected void tearDown() throws Exception { + BrokerService broker = (BrokerService) context.getBean("localbroker"); + broker.stop(); + broker = (BrokerService) context.getBean("default"); + broker.stop(); + super.tearDown(); + } + + public void testNoFactorySet() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.addAll(DEFAULT_TOKENS); + + command.execute(tokens); + assertNotNull(command.getConnectionFactory()); + assertTrue(command.getConnectionFactory() instanceof ActiveMQConnectionFactory); + } + + public void testFactorySet() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--factory"); + tokens.add(DummyConnectionFactory.class.getCanonicalName()); + tokens.addAll(DEFAULT_TOKENS); + + command.execute(tokens); + + assertNotNull(command.getConnectionFactory()); + assertTrue("wrong instance returned: " + + command.getConnectionFactory().getClass().getName(), command + .getConnectionFactory() instanceof DummyConnectionFactory); + } + + public void testFactorySetWrong1() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--factory"); + tokens + .add("org.apache.activemq.console.command.TestAMQ3410.DoesntExistFactory"); + tokens.addAll(DEFAULT_TOKENS); + + try { + command.execute(tokens); + } catch (Throwable cause) { + while (null != cause) { + if (cause instanceof java.lang.ClassNotFoundException) + return; + cause = cause.getCause(); + } + } + assertFalse("No exception caught", true); + } + + public void testFactorySetWrong2() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--factory"); + tokens.add(InvalidConnectionFactory.class.getCanonicalName()); + tokens.addAll(DEFAULT_TOKENS); + + try { + command.execute(tokens); + } catch (Throwable e) { + Throwable cause = e; + while (null != cause) { + if (cause instanceof java.lang.NoSuchMethodException) + return; + cause = cause.getCause(); + } + assertFalse(e.toString(), true); + } + assertFalse("No exception caught", true); + } + + public void testFactorySetWrong3() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--factory"); + tokens.add("java.lang.Object"); + tokens.addAll(DEFAULT_TOKENS); + + try { + command.execute(tokens); + } catch (Throwable cause) { + while (null != cause) { + if (cause instanceof java.lang.NoSuchMethodException) + return; + cause = cause.getCause(); + } + } + assertFalse(true); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/AMQ3411Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/AMQ3411Test.java new file mode 100644 index 0000000000..8930b2c156 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/AMQ3411Test.java @@ -0,0 +1,197 @@ +/** + * 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.console.command; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.console.CommandContext; +import org.apache.activemq.console.formatter.CommandShellOutputFormatter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class AMQ3411Test extends TestCase { + @SuppressWarnings("unused") + private static final Logger LOG = LoggerFactory + .getLogger(AMQ3411Test.class); + private static final Collection DEFAULT_OPTIONS = Arrays + .asList(new String[] { "--amqurl", "tcp://localhost:61616", }); + + private static final Collection DEFAULT_TOKENS = Arrays + .asList(new String[] { "FOO.QUEUE" }); + protected AbstractApplicationContext context; + protected static final String origPassword = "ABCDEFG"; + + protected void setUp() throws Exception { + super.setUp(); + + context = createApplicationContext(); + + } + + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/console/command/activemq.xml"); + } + + protected void tearDown() throws Exception { + BrokerService broker = (BrokerService) context.getBean("localbroker"); + broker.stop(); + broker = (BrokerService) context.getBean("default"); + broker.stop(); + super.tearDown(); + } + + public void testNoFactorySet() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.addAll(DEFAULT_TOKENS); + + command.execute(tokens); + + assertNotNull(command.getPasswordFactory()); + assertTrue(command.getPasswordFactory() instanceof DefaultPasswordFactory); + assertNull(command.getPassword()); + } + + public void testUsernamePasswordSet() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + String username = "user"; + String password = "password"; + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--password"); + tokens.add(password); + + tokens.add("--user"); + tokens.add(username); + tokens.addAll(DEFAULT_TOKENS); + + command.execute(tokens); + + assertNotNull(command.getPasswordFactory()); + assertTrue(command.getPasswordFactory() instanceof DefaultPasswordFactory); + assertEquals(password, command.getPassword()); + assertEquals(username, command.getUsername()); + } + + public void testFactorySet() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--passwordFactory"); + tokens.add(LowercasingPasswordFactory.class.getCanonicalName()); + tokens.add("--password"); + tokens.add(origPassword); + tokens.addAll(DEFAULT_TOKENS); + + command.execute(tokens); + assertNotNull(command.getPasswordFactory()); + assertTrue(command.getPasswordFactory() instanceof LowercasingPasswordFactory); + + // validate that the factory is indeed being used for the password. + assertEquals(origPassword.toLowerCase(), command.getPassword()); + } + + public void testFactorySetWrong1() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--passwordFactory"); + tokens + .add("org.apache.activemq.console.command.TestAMQ3411.DoesntExistFactory"); + tokens.add("--password"); + tokens.add(origPassword); + + tokens.addAll(DEFAULT_TOKENS); + + try { + command.execute(tokens); + } catch (Throwable e) { + Throwable cause = e; + while (null != cause) { + if (cause instanceof java.lang.ClassNotFoundException) + return; + cause = cause.getCause(); + } + assertFalse(e.toString(), true); + } + assertFalse("No exception caught", true); + } + + public void testFactorySetWrong2() throws Exception { + AmqBrowseCommand command = new AmqBrowseCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + command.setCommandContext(context); + + List tokens = new ArrayList(); + tokens.addAll(DEFAULT_OPTIONS); + tokens.add("--passwordFactory"); + tokens.add("java.lang.Object"); + tokens.add("--password"); + tokens.add(origPassword); + tokens.addAll(DEFAULT_TOKENS); + + try { + command.execute(tokens); + } catch (Throwable e) { + Throwable cause = e; + while (null != cause) { + if (cause instanceof java.lang.ClassCastException) + return; + cause = cause.getCause(); + } + assertFalse(e.toString(), true); + } + assertFalse("No exception caught", true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/DummyConnectionFactory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/DummyConnectionFactory.java new file mode 100644 index 0000000000..03f9fc5cc5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/DummyConnectionFactory.java @@ -0,0 +1,44 @@ +/** + * 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.console.command; + +import org.apache.activemq.ActiveMQConnectionFactory; + +import java.net.URI; + +public class DummyConnectionFactory extends ActiveMQConnectionFactory { + public DummyConnectionFactory() { + super(); + } + + public DummyConnectionFactory(String userName, String password, String brokerURL) { + super(userName, password, brokerURL); + } + + public DummyConnectionFactory(String userName, String password, URI brokerURL) { + super(userName, password, brokerURL); + } + + public DummyConnectionFactory(String brokerURL) { + super(brokerURL); + } + + public DummyConnectionFactory(URI brokerURL) { + super(brokerURL); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/InvalidConnectionFactory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/InvalidConnectionFactory.java new file mode 100644 index 0000000000..fa57684a28 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/InvalidConnectionFactory.java @@ -0,0 +1,23 @@ +/** + * 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.console.command; + +import org.apache.activemq.ActiveMQConnectionFactory; + +public class InvalidConnectionFactory extends ActiveMQConnectionFactory { + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/LowercasingPasswordFactory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/LowercasingPasswordFactory.java new file mode 100644 index 0000000000..a0f9b05ec7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/LowercasingPasswordFactory.java @@ -0,0 +1,25 @@ +/** + * 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.console.command; + +public class LowercasingPasswordFactory implements PasswordFactory { + @Override + public String getPassword(String password) { + return password.toLowerCase(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/PurgeCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/PurgeCommandTest.java new file mode 100644 index 0000000000..57fffa0dfb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/PurgeCommandTest.java @@ -0,0 +1,464 @@ +/** + * 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.console.command; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.QueueConnection; +import javax.jms.QueueRequestor; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.console.CommandContext; +import org.apache.activemq.console.formatter.CommandShellOutputFormatter; +import org.apache.activemq.console.util.JmxMBeansUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class PurgeCommandTest extends TestCase { + private static final Logger LOG = LoggerFactory + .getLogger(PurgeCommandTest.class); + + protected static final int MESSAGE_COUNT = 10; + protected static final String PROPERTY_NAME = "XTestProperty"; + protected static final String PROPERTY_VALUE = "1:1"; + + // check for existence of property + protected static final String MSG_SEL_WITH_PROPERTY = PROPERTY_NAME + + " is not null"; + + // check for non-existence of property + protected static final String MSG_SEL_WITHOUT_PROPERTY = PROPERTY_NAME + + " is null"; + + // complex message selector query using XTestProperty and JMSPriority + protected static final String MSG_SEL_COMPLEX = PROPERTY_NAME + "='" + + "1:1" + "',JMSPriority>3"; + + // complex message selector query using XTestProperty AND JMSPriority + // but in SQL-92 syntax + protected static final String MSG_SEL_COMPLEX_SQL_AND = "(" + PROPERTY_NAME + "='" + + "1:1" + "') AND (JMSPriority>3)"; + + // complex message selector query using XTestProperty OR JMSPriority + // but in SQL-92 syntax + protected static final String MSG_SEL_COMPLEX_SQL_OR = "(" + PROPERTY_NAME + "='" + + "1:1" + "') OR (JMSPriority>3)"; + + + protected static final String QUEUE_NAME = "org.apache.activemq.network.jms.QueueBridgeTest"; + + protected AbstractApplicationContext context; + protected QueueConnection localConnection; + protected QueueRequestor requestor; + protected QueueSession requestServerSession; + protected MessageConsumer requestServerConsumer; + protected MessageProducer requestServerProducer; + protected Queue theQueue; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + context = createApplicationContext(); + + createConnections(); + + requestServerSession = localConnection.createQueueSession(false, + Session.AUTO_ACKNOWLEDGE); + theQueue = requestServerSession.createQueue(QUEUE_NAME); + requestServerConsumer = requestServerSession.createConsumer(theQueue); + requestServerProducer = requestServerSession.createProducer(null); + + QueueSession session = localConnection.createQueueSession(false, + Session.AUTO_ACKNOWLEDGE); + requestor = new QueueRequestor(session, theQueue); + } + + protected void createConnections() throws JMSException { + ActiveMQConnectionFactory fac = (ActiveMQConnectionFactory) context + .getBean("localFactory"); + localConnection = fac.createQueueConnection(); + localConnection.start(); + } + + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/console/command/activemq.xml"); + } + + @Override + protected void tearDown() throws Exception { + localConnection.close(); + BrokerService broker = (BrokerService) context.getBean("localbroker"); + broker.stop(); + broker = (BrokerService) context.getBean("default"); + broker.stop(); + super.tearDown(); + } + + public int getMessageCount(QueueBrowser browser, String prefix) throws JMSException { + Enumeration e = browser.getEnumeration(); + int with = 0; + while (e.hasMoreElements()) { + Object o = e.nextElement(); + System.out.println(prefix + o); + with++; + } + return with; + } + + public void cleanup() throws JMSException { + for (int i = 0; i < MESSAGE_COUNT * 2; i++) { + requestServerConsumer.receive(); + } + } + + protected MBeanServerConnection createJmxConnection() throws IOException { + return ManagementFactory.getPlatformMBeanServer(); + } + + @SuppressWarnings("unchecked") + public void purgeAllMessages() throws IOException, Exception { + List queueList = JmxMBeansUtil.queryMBeans( + createJmxConnection(), "type=Broker,brokerName=localbroker,destinationType=Queue,destinationName=*"); + for (ObjectInstance oi : queueList) { + ObjectName queueName = oi.getObjectName(); + LOG.info("Purging all messages in queue: " + + queueName.getKeyProperty("Destination")); + createJmxConnection().invoke(queueName, "purge", + new Object[] {}, new String[] {}); + } + } + + public void addMessages() throws IOException, Exception { + // first clean out any messages that may exist. + purgeAllMessages(); + + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage msg = requestServerSession + .createTextMessage("test msg: " + i); + msg.setStringProperty(PROPERTY_NAME, PROPERTY_VALUE); + requestServerProducer.send(theQueue, msg); + } + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage msg = requestServerSession + .createTextMessage("test msg: " + i); + requestServerProducer.send(theQueue, msg); + } + + } + + public void validateCounts(int expectedWithCount, int expectedWithoutCount, + int expectedAllCount) throws JMSException { + QueueBrowser withPropertyBrowser = requestServerSession.createBrowser( + theQueue, MSG_SEL_WITH_PROPERTY); + QueueBrowser withoutPropertyBrowser = requestServerSession + .createBrowser(theQueue, MSG_SEL_WITHOUT_PROPERTY); + QueueBrowser allBrowser = requestServerSession.createBrowser(theQueue); + + int withCount = getMessageCount(withPropertyBrowser, "withProperty "); + int withoutCount = getMessageCount(withoutPropertyBrowser, + "withoutProperty "); + int allCount = getMessageCount(allBrowser, "allMessages "); + + withPropertyBrowser.close(); + withoutPropertyBrowser.close(); + allBrowser.close(); + + assertEquals("Expected withCount to be " + expectedWithCount + " was " + + withCount, expectedWithCount, withCount); + assertEquals("Expected withoutCount to be " + expectedWithoutCount + + " was " + withoutCount, expectedWithoutCount, withoutCount); + assertEquals("Expected allCount to be " + expectedAllCount + " was " + + allCount, expectedAllCount, allCount); + LOG.info("withCount = " + withCount + "\n withoutCount = " + + withoutCount + "\n allCount = " + allCount + "\n = " + "\n"); + } + + /** + * This test ensures that the queueViewMbean will work. + * + * @throws Exception + */ + @SuppressWarnings("unchecked") + public void testQueueViewMbean() throws Exception { + + try { + addMessages(); + + validateCounts(MESSAGE_COUNT, MESSAGE_COUNT, MESSAGE_COUNT * 2); + + List tokens = Arrays.asList(new String[] { "*" }); + for (String token : tokens) { + List queueList = JmxMBeansUtil.queryMBeans( + createJmxConnection(), "type=Broker,brokerName=localbroker,destinationType=Queue,destinationName=" + + token); + + for (ObjectInstance queue : queueList) { + ObjectName queueName = queue + .getObjectName(); + QueueViewMBean proxy = MBeanServerInvocationHandler + .newProxyInstance(createJmxConnection(), queueName, + QueueViewMBean.class, true); + int removed = proxy + .removeMatchingMessages(MSG_SEL_WITH_PROPERTY); + LOG.info("Removed: " + removed); + } + } + + validateCounts(0, MESSAGE_COUNT, MESSAGE_COUNT); + + } finally { + purgeAllMessages(); + } + } + + public void testPurgeCommandSimpleSelector() throws Exception { + try { + PurgeCommand purgeCommand = new PurgeCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + purgeCommand.setCommandContext(context); + purgeCommand.setJmxUseLocal(true); + + List tokens = new ArrayList(); + tokens.add("--msgsel"); + tokens.add(MSG_SEL_WITH_PROPERTY); + + addMessages(); + validateCounts(MESSAGE_COUNT, MESSAGE_COUNT, MESSAGE_COUNT * 2); + + purgeCommand.execute(tokens); + + validateCounts(0, MESSAGE_COUNT, MESSAGE_COUNT); + } finally { + purgeAllMessages(); + } + } + + public void testPurgeCommandComplexSelector() throws Exception { + try { + PurgeCommand purgeCommand = new PurgeCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + purgeCommand.setCommandContext(context); + purgeCommand.setJmxUseLocal(true); + + List tokens = new ArrayList(); + tokens.add("--msgsel"); + tokens.add(MSG_SEL_COMPLEX); + + addMessages(); + validateCounts(MESSAGE_COUNT, MESSAGE_COUNT, MESSAGE_COUNT * 2); + + purgeCommand.execute(tokens); + + QueueBrowser withPropertyBrowser = requestServerSession.createBrowser( + theQueue, MSG_SEL_COMPLEX); + QueueBrowser allBrowser = requestServerSession.createBrowser(theQueue); + + int withCount = getMessageCount(withPropertyBrowser, "withProperty "); + int allCount = getMessageCount(allBrowser, "allMessages "); + + withPropertyBrowser.close(); + allBrowser.close(); + + assertEquals("Expected withCount to be " + "0" + " was " + + withCount, 0, withCount); + assertEquals("Expected allCount to be " + MESSAGE_COUNT + " was " + + allCount, MESSAGE_COUNT, allCount); + LOG.info("withCount = " + withCount + "\n allCount = " + + allCount + "\n = " + "\n"); + } finally { + purgeAllMessages(); + } + } + + public void testPurgeCommandComplexSQLSelector_AND() throws Exception { + try { + + String one = "ID:mac.fritz.box:1213242.3231.1:1:1:100"; + String two = "\\*:100"; + try { + if (one.matches(two)) + LOG.info("String matches."); + else + LOG.info("string does not match."); + } catch (Exception ex) { + LOG.error(ex.getMessage()); + } + + PurgeCommand purgeCommand = new PurgeCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + purgeCommand.setCommandContext(context); + purgeCommand.setJmxUseLocal(true); + + List tokens = new ArrayList(); + tokens.add("--msgsel"); + tokens.add(MSG_SEL_COMPLEX_SQL_AND); + + addMessages(); + validateCounts(MESSAGE_COUNT, MESSAGE_COUNT, MESSAGE_COUNT * 2); + + purgeCommand.execute(tokens); + + QueueBrowser withPropertyBrowser = requestServerSession.createBrowser( + theQueue, MSG_SEL_COMPLEX_SQL_AND); + QueueBrowser allBrowser = requestServerSession.createBrowser(theQueue); + + int withCount = getMessageCount(withPropertyBrowser, "withProperty "); + int allCount = getMessageCount(allBrowser, "allMessages "); + + withPropertyBrowser.close(); + allBrowser.close(); + + assertEquals("Expected withCount to be " + "0" + " was " + + withCount, 0, withCount); + assertEquals("Expected allCount to be " + MESSAGE_COUNT + " was " + + allCount, MESSAGE_COUNT, allCount); + LOG.info("withCount = " + withCount + "\n allCount = " + + allCount + "\n = " + "\n"); + } finally { + purgeAllMessages(); + } + } + + public void testPurgeCommandComplexSQLSelector_OR() throws Exception { + try { + PurgeCommand purgeCommand = new PurgeCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + purgeCommand.setCommandContext(context); + purgeCommand.setJmxUseLocal(true); + + List tokens = new ArrayList(); + tokens.add("--msgsel"); + tokens.add(MSG_SEL_COMPLEX_SQL_OR); + + addMessages(); + validateCounts(MESSAGE_COUNT, MESSAGE_COUNT, MESSAGE_COUNT * 2); + + purgeCommand.execute(tokens); + + QueueBrowser withPropertyBrowser = requestServerSession.createBrowser( + theQueue, MSG_SEL_COMPLEX_SQL_OR); + QueueBrowser allBrowser = requestServerSession.createBrowser(theQueue); + + int withCount = getMessageCount(withPropertyBrowser, "withProperty "); + int allCount = getMessageCount(allBrowser, "allMessages "); + + withPropertyBrowser.close(); + allBrowser.close(); + + assertEquals("Expected withCount to be 0 but was " + + withCount, 0, withCount); + assertEquals("Expected allCount to be 0 but was " + + allCount, 0, allCount); + LOG.info("withCount = " + withCount + "\n allCount = " + + allCount + "\n = " + "\n"); + } finally { + purgeAllMessages(); + } + } + + public void testDummy() throws Exception { + try { + + String one = "ID:mac.fritz.box:1213242.3231.1:1:1:100"; + String two = "ID*:100"; + try { + if (one.matches(two)) + LOG.info("String matches."); + else + LOG.info("string does not match."); + } catch (Exception ex) { + LOG.error(ex.getMessage()); + } + + PurgeCommand purgeCommand = new PurgeCommand(); + CommandContext context = new CommandContext(); + + context.setFormatter(new CommandShellOutputFormatter(System.out)); + + purgeCommand.setCommandContext(context); + purgeCommand.setJmxUseLocal(true); + + List tokens = new ArrayList(); + tokens.add("--msgsel"); + tokens.add("(XTestProperty LIKE '1:*') AND (JMSPriority>3)"); + + addMessages(); + + purgeCommand.execute(tokens); + + /* + QueueBrowser withPropertyBrowser = requestServerSession.createBrowser( + theQueue, MSG_SEL_COMPLEX_SQL_AND); + QueueBrowser allBrowser = requestServerSession.createBrowser(theQueue); + + int withCount = getMessageCount(withPropertyBrowser, "withProperty "); + int allCount = getMessageCount(allBrowser, "allMessages "); + + withPropertyBrowser.close(); + allBrowser.close(); + + assertEquals("Expected withCount to be " + "0" + " was " + + withCount, 0, withCount); + assertEquals("Expected allCount to be " + MESSAGE_COUNT + " was " + + allCount, MESSAGE_COUNT, allCount); + LOG.info("withCount = " + withCount + "\n allCount = " + + allCount + "\n = " + "\n"); + */ + } finally { + purgeAllMessages(); + } + } + + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/activemq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/activemq.xml new file mode 100644 index 0000000000..b2aaf16a09 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/console/command/activemq.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + tcp://localhost:61234 + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/conversions/AmqpAndMqttTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/conversions/AmqpAndMqttTest.java new file mode 100644 index 0000000000..3c0f474b8a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/conversions/AmqpAndMqttTest.java @@ -0,0 +1,120 @@ +/** + * 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.conversions; + +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.qpid.amqp_1_0.jms.impl.ConnectionFactoryImpl; +import org.apache.qpid.amqp_1_0.jms.impl.QueueImpl; +import org.apache.qpid.amqp_1_0.jms.impl.TopicImpl; +import org.fusesource.mqtt.client.BlockingConnection; +import org.fusesource.mqtt.client.MQTT; +import org.fusesource.mqtt.client.QoS; + +import javax.jms.*; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; + +/** + */ +public class AmqpAndMqttTest extends CombinationTestSupport { + + protected BrokerService broker; + private TransportConnector amqpConnector; + private TransportConnector mqttConnector; + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + } + + @Override + protected void tearDown() throws Exception { + if( broker!=null ) { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + } + super.tearDown(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + amqpConnector = broker.addConnector("amqp://0.0.0.0:0"); + mqttConnector = broker.addConnector("mqtt://0.0.0.0:0"); + return broker; + } + + + public void testFromMqttToAmqp() throws Exception { + Connection amqp = createAmqpConnection(); + Session session = amqp.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(session.createTopic("topic://FOO")); + + final BlockingConnection mqtt = createMQTTConnection().blockingConnection(); + mqtt.connect(); + byte[] payload = bytes("Hello World"); + mqtt.publish("FOO", payload, QoS.AT_LEAST_ONCE, false); + mqtt.disconnect(); + + Message msg = consumer.receive(1000 * 5); + assertNotNull(msg); + assertTrue(msg instanceof BytesMessage); + + BytesMessage bmsg = (BytesMessage) msg; + byte[] actual = new byte[(int) bmsg.getBodyLength()]; + bmsg.readBytes(actual); + assertTrue(Arrays.equals(actual, payload)); + amqp.close(); + } + + private byte[] bytes(String value) { + try { + return value.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + + protected MQTT createMQTTConnection() throws Exception { + MQTT mqtt = new MQTT(); + mqtt.setConnectAttemptsMax(1); + mqtt.setReconnectAttemptsMax(0); + mqtt.setHost("localhost", mqttConnector.getConnectUri().getPort()); + return mqtt; + } + + public Connection createAmqpConnection() throws Exception { + final ConnectionFactoryImpl factory = new ConnectionFactoryImpl("localhost", amqpConnector.getConnectUri().getPort(), "admin", "password"); + final Connection connection = factory.createConnection(); + connection.setExceptionListener(new ExceptionListener() { + @Override + public void onException(JMSException exception) { + exception.printStackTrace(); + } + }); + connection.start(); + return connection; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/DefaultQueueSender.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/DefaultQueueSender.java new file mode 100644 index 0000000000..98ca666cb3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/DefaultQueueSender.java @@ -0,0 +1,111 @@ +/** + * 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. + */ + +/** + * The SimpleQueueSender class consists only of a main method, + * which sends several messages to a queue. + * + * Run this program in conjunction with SimpleQueueReceiver. + * Specify a queue name on the command line when you run the + * program. By default, the program sends one message. Specify + * a number after the queue name to send that number of messages. + */ +package org.apache.activemq.demo; + +// START SNIPPET: demo + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A simple queue sender which does not use JNDI + * + * + */ +public final class DefaultQueueSender { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultQueueSender.class); + + private DefaultQueueSender() { + } + + public static void main(String[] args) { + + String uri = "tcp://localhost:61616"; + String text = "Hello World!"; + + Connection connection = null; + + if (args.length < 1) { + printUsage(); + System.exit(1); + } + + int idx = 0; + String arg = args[0]; + if (arg.equals("-uri")) { + if (args.length == 1) { + printUsage(); + System.exit(1); + } + uri = args[1]; + idx += 2; + } + String queueName = args[idx]; + LOG.info("Connecting to: " + uri); + LOG.info("Queue name is " + queueName); + + if (++idx < args.length) { + text = args[idx]; + } + + try { + ConnectionFactory factory = new ActiveMQConnectionFactory(uri); + connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(queueName); + MessageProducer producer = session.createProducer(destination); + + Message message = session.createTextMessage(text); + producer.send(message); + } catch (JMSException e) { + LOG.info("Exception occurred: " + e.toString()); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (JMSException e) { + } + } + } + } + + protected static void printUsage() { + System.out.println("Usage: java DefaultQueueSender [-uri ] " + " []"); + } +} + +// END SNIPPET: demo diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleConsumer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleConsumer.java new file mode 100644 index 0000000000..9b515ace24 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleConsumer.java @@ -0,0 +1,130 @@ +/** + * 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. + */ + +/** + * The SimpleQueueReceiver class consists only of a main method, + * which fetches one or more messages from a queue using + * synchronous message delivery. Run this program in conjunction + * with SimpleQueueSender. Specify a queue name on the command + * line when you run the program. + */ +package org.apache.activemq.demo; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * A simple polymorphic JMS consumer which can work with Queues or Topics which + * uses JNDI to lookup the JMS connection factory and destination + * + * + */ +public final class SimpleConsumer { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(SimpleConsumer.class); + + private SimpleConsumer() { + } + + /** + * @param args the queue used by the example + */ + public static void main(String[] args) { + String destinationName = null; + Context jndiContext = null; + ConnectionFactory connectionFactory = null; + Connection connection = null; + Session session = null; + Destination destination = null; + MessageConsumer consumer = null; + + /* + * Read destination name from command line and display it. + */ + if (args.length != 1) { + LOG.info("Usage: java SimpleConsumer "); + System.exit(1); + } + destinationName = args[0]; + LOG.info("Destination name is " + destinationName); + + /* + * Create a JNDI API InitialContext object + */ + try { + jndiContext = new InitialContext(); + } catch (NamingException e) { + LOG.info("Could not create JNDI API " + "context: " + e.toString()); + System.exit(1); + } + + /* + * Look up connection factory and destination. + */ + try { + connectionFactory = (ConnectionFactory)jndiContext.lookup("ConnectionFactory"); + destination = (Destination)jndiContext.lookup(destinationName); + } catch (NamingException e) { + LOG.info("JNDI API lookup failed: " + e.toString()); + System.exit(1); + } + + /* + * Create connection. Create session from connection; false means + * session is not transacted. Create receiver, then start message + * delivery. Receive all text messages from destination until a non-text + * message is received indicating end of message stream. Close + * connection. + */ + try { + connection = connectionFactory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(destination); + connection.start(); + while (true) { + Message m = consumer.receive(1); + if (m != null) { + if (m instanceof TextMessage) { + TextMessage message = (TextMessage)m; + LOG.info("Reading message: " + message.getText()); + } else { + break; + } + } + } + } catch (JMSException e) { + LOG.info("Exception occurred: " + e); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (JMSException e) { + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleProducer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleProducer.java new file mode 100644 index 0000000000..85061c847c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleProducer.java @@ -0,0 +1,139 @@ +/** + * 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. + */ + +/** + * The SimpleQueueSender class consists only of a main method, + * which sends several messages to a queue. + * + * Run this program in conjunction with SimpleQueueReceiver. + * Specify a queue name on the command line when you run the + * program. By default, the program sends one message. Specify + * a number after the queue name to send that number of messages. + */ +package org.apache.activemq.demo; + +// START SNIPPET: demo + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A simple polymorphic JMS producer which can work with Queues or Topics which + * uses JNDI to lookup the JMS connection factory and destination + * + * + */ +public final class SimpleProducer { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleProducer.class); + + private SimpleProducer() { + } + + /** + * @param args the destination name to send to and optionally, the number of + * messages to send + */ + public static void main(String[] args) { + Context jndiContext = null; + ConnectionFactory connectionFactory = null; + Connection connection = null; + Session session = null; + Destination destination = null; + MessageProducer producer = null; + String destinationName = null; + final int numMsgs; + + if ((args.length < 1) || (args.length > 2)) { + LOG.info("Usage: java SimpleProducer []"); + System.exit(1); + } + destinationName = args[0]; + LOG.info("Destination name is " + destinationName); + if (args.length == 2) { + numMsgs = (new Integer(args[1])).intValue(); + } else { + numMsgs = 1; + } + + /* + * Create a JNDI API InitialContext object + */ + try { + jndiContext = new InitialContext(); + } catch (NamingException e) { + LOG.info("Could not create JNDI API context: " + e.toString()); + System.exit(1); + } + + /* + * Look up connection factory and destination. + */ + try { + connectionFactory = (ConnectionFactory)jndiContext.lookup("ConnectionFactory"); + destination = (Destination)jndiContext.lookup(destinationName); + } catch (NamingException e) { + LOG.info("JNDI API lookup failed: " + e); + System.exit(1); + } + + /* + * Create connection. Create session from connection; false means + * session is not transacted. Create sender and text message. Send + * messages, varying text slightly. Send end-of-messages message. + * Finally, close connection. + */ + try { + connection = connectionFactory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(destination); + TextMessage message = session.createTextMessage(); + for (int i = 0; i < numMsgs; i++) { + message.setText("This is message " + (i + 1)); + LOG.info("Sending message: " + message.getText()); + producer.send(message); + } + + /* + * Send a non-text control message indicating end of messages. + */ + producer.send(session.createMessage()); + } catch (JMSException e) { + LOG.info("Exception occurred: " + e); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (JMSException e) { + } + } + } + } +} + +// END SNIPPET: demo diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleQueueReceiver.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleQueueReceiver.java new file mode 100644 index 0000000000..791efa1d18 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleQueueReceiver.java @@ -0,0 +1,130 @@ +/** + * 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. + */ + +/** + * The SimpleQueueReceiver class consists only of a main method, + * which fetches one or more messages from a queue using + * synchronous message delivery. Run this program in conjunction + * with SimpleQueueSender. Specify a queue name on the command + * line when you run the program. + */ +package org.apache.activemq.demo; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueReceiver; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class SimpleQueueReceiver { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleQueueReceiver.class); + + private SimpleQueueReceiver() { + } + + /** + * Main method. + * + * @param args the queue used by the example + */ + public static void main(String[] args) { + String queueName = null; + Context jndiContext = null; + QueueConnectionFactory queueConnectionFactory = null; + QueueConnection queueConnection = null; + QueueSession queueSession = null; + Queue queue = null; + QueueReceiver queueReceiver = null; + TextMessage message = null; + + /* + * Read queue name from command line and display it. + */ + if (args.length != 1) { + LOG.info("Usage: java " + "SimpleQueueReceiver "); + System.exit(1); + } + queueName = args[0]; + LOG.info("Queue name is " + queueName); + + /* + * Create a JNDI API InitialContext object if none exists yet. + */ + try { + jndiContext = new InitialContext(); + } catch (NamingException e) { + LOG.info("Could not create JNDI API " + "context: " + e.toString()); + System.exit(1); + } + + /* + * Look up connection factory and queue. If either does not exist, exit. + */ + try { + queueConnectionFactory = (QueueConnectionFactory)jndiContext.lookup("QueueConnectionFactory"); + queue = (Queue)jndiContext.lookup(queueName); + } catch (NamingException e) { + LOG.info("JNDI API lookup failed: " + e.toString()); + System.exit(1); + } + + /* + * Create connection. Create session from connection; false means + * session is not transacted. Create receiver, then start message + * delivery. Receive all text messages from queue until a non-text + * message is received indicating end of message stream. Close + * connection. + */ + try { + queueConnection = queueConnectionFactory.createQueueConnection(); + queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + queueReceiver = queueSession.createReceiver(queue); + queueConnection.start(); + while (true) { + Message m = queueReceiver.receive(1); + if (m != null) { + if (m instanceof TextMessage) { + message = (TextMessage)m; + LOG.info("Reading message: " + message.getText()); + } else { + break; + } + } + } + } catch (JMSException e) { + LOG.info("Exception occurred: " + e.toString()); + } finally { + if (queueConnection != null) { + try { + queueConnection.close(); + } catch (JMSException e) { + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleQueueSender.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleQueueSender.java new file mode 100644 index 0000000000..22ee403be8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/demo/SimpleQueueSender.java @@ -0,0 +1,137 @@ +/** + * 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. + */ + +/** + * The SimpleQueueSender class consists only of a main method, + * which sends several messages to a queue. + * + * Run this program in conjunction with SimpleQueueReceiver. + * Specify a queue name on the command line when you run the + * program. By default, the program sends one message. Specify + * a number after the queue name to send that number of messages. + */ +package org.apache.activemq.demo; + +// START SNIPPET: demo + +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class SimpleQueueSender { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleQueueSender.class); + + private SimpleQueueSender() { + } + + /** + * Main method. + * + * @param args the queue used by the example and, optionally, the number of + * messages to send + */ + public static void main(String[] args) { + String queueName = null; + Context jndiContext = null; + QueueConnectionFactory queueConnectionFactory = null; + QueueConnection queueConnection = null; + QueueSession queueSession = null; + Queue queue = null; + QueueSender queueSender = null; + TextMessage message = null; + final int numMsgs; + + if ((args.length < 1) || (args.length > 2)) { + LOG.info("Usage: java SimpleQueueSender " + " []"); + System.exit(1); + } + queueName = args[0]; + LOG.info("Queue name is " + queueName); + if (args.length == 2) { + numMsgs = (new Integer(args[1])).intValue(); + } else { + numMsgs = 1; + } + + /* + * Create a JNDI API InitialContext object if none exists yet. + */ + try { + jndiContext = new InitialContext(); + } catch (NamingException e) { + LOG.info("Could not create JNDI API context: " + e.toString()); + System.exit(1); + } + + /* + * Look up connection factory and queue. If either does not exist, exit. + */ + try { + queueConnectionFactory = (QueueConnectionFactory)jndiContext.lookup("QueueConnectionFactory"); + queue = (Queue)jndiContext.lookup(queueName); + } catch (NamingException e) { + LOG.info("JNDI API lookup failed: " + e); + System.exit(1); + } + + /* + * Create connection. Create session from connection; false means + * session is not transacted. Create sender and text message. Send + * messages, varying text slightly. Send end-of-messages message. + * Finally, close connection. + */ + try { + queueConnection = queueConnectionFactory.createQueueConnection(); + queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + queueSender = queueSession.createSender(queue); + message = queueSession.createTextMessage(); + for (int i = 0; i < numMsgs; i++) { + message.setText("This is message " + (i + 1)); + LOG.info("Sending message: " + message.getText()); + queueSender.send(message); + } + + /* + * Send a non-text control message indicating end of messages. + */ + queueSender.send(queueSession.createMessage()); + } catch (JMSException e) { + LOG.info("Exception occurred: " + e.toString()); + } finally { + if (queueConnection != null) { + try { + queueConnection.close(); + } catch (JMSException e) { + } + } + } + } +} + +// END SNIPPET: demo diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationFilterTest.java new file mode 100644 index 0000000000..95af3942e9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationFilterTest.java @@ -0,0 +1,65 @@ +/** + * 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.filter; + +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +import junit.framework.TestCase; + +public class DestinationFilterTest extends TestCase { + + public void testPrefixFilter() throws Exception { + DestinationFilter filter = DestinationFilter.parseFilter(new ActiveMQQueue(">")); + assertTrue("Filter not parsed well: " + filter.getClass(), filter instanceof PrefixDestinationFilter); + System.out.println(filter); + assertFalse("Filter matched wrong destination type", filter.matches(new ActiveMQTopic(">"))); + } + + public void testWildcardFilter() throws Exception { + DestinationFilter filter = DestinationFilter.parseFilter(new ActiveMQQueue("A.*")); + assertTrue("Filter not parsed well: " + filter.getClass(), filter instanceof WildcardDestinationFilter); + assertFalse("Filter matched wrong destination type", filter.matches(new ActiveMQTopic("A.B"))); + } + + public void testCompositeFilter() throws Exception { + DestinationFilter filter = DestinationFilter.parseFilter(new ActiveMQQueue("A.B,B.C")); + assertTrue("Filter not parsed well: " + filter.getClass(), filter instanceof CompositeDestinationFilter); + assertFalse("Filter matched wrong destination type", filter.matches(new ActiveMQTopic("A.B"))); + } + + public void testMatchesChild() throws Exception{ + DestinationFilter filter = DestinationFilter.parseFilter(new ActiveMQQueue("A.*.C")); + assertFalse("Filter matched wrong destination type", filter.matches(new ActiveMQTopic("A.B"))); + assertTrue("Filter did not match", filter.matches(new ActiveMQQueue("A.B.C"))); + + filter = DestinationFilter.parseFilter(new ActiveMQQueue("A.*")); + assertTrue("Filter did not match", filter.matches(new ActiveMQQueue("A.B"))); + assertFalse("Filter did match", filter.matches(new ActiveMQQueue("A"))); + } + + public void testMatchesAny() throws Exception{ + DestinationFilter filter = DestinationFilter.parseFilter(new ActiveMQQueue("A.>.>")); + + assertTrue("Filter did not match", filter.matches(new ActiveMQQueue("A.C"))); + + assertFalse("Filter did match", filter.matches(new ActiveMQQueue("B"))); + assertTrue("Filter did not match", filter.matches(new ActiveMQQueue("A.B"))); + assertTrue("Filter did not match", filter.matches(new ActiveMQQueue("A.B.C.D.E.F"))); + assertTrue("Filter did not match", filter.matches(new ActiveMQQueue("A"))); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java new file mode 100644 index 0000000000..42edaf43fa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java @@ -0,0 +1,52 @@ +/** + * 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.filter; + +import junit.framework.TestCase; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTopic; + +public class DestinationMapMemoryTest extends TestCase { + + public void testLongDestinationPath() throws Exception { + ActiveMQTopic d1 = new ActiveMQTopic("1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18"); + DestinationMap map = new DestinationMap(); + map.put(d1, d1); + } + + public void testVeryLongestinationPaths() throws Exception { + + for (int i = 1; i < 100; i++) { + String name = "1"; + for (int j = 2; j <= i; j++) { + name += "." + j; + } + // System.out.println("Checking: " + name); + try { + ActiveMQDestination d1 = createDestination(name); + DestinationMap map = new DestinationMap(); + map.put(d1, d1); + } catch (Throwable e) { + fail("Destination name too long: " + name + " : " + e); + } + } + } + + protected ActiveMQDestination createDestination(String name) { + return new ActiveMQTopic(name); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java new file mode 100644 index 0000000000..21dd60d946 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java @@ -0,0 +1,45 @@ +/** + * 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.filter; + +import java.util.Set; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQTempQueue; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.util.IdGenerator; + +public class DestinationMapTempDestinationTest extends TestCase { + + public void testtestTempDestinations() throws Exception { + ConnectionId id = new ConnectionId(new IdGenerator().generateId()); + DestinationMap map = new DestinationMap(); + Object value = new Object(); + int count = 1000; + for (int i = 0; i < count; i++) { + ActiveMQTempQueue queue = new ActiveMQTempQueue(id, i); + map.put(queue, value); + } + for (int i = 0; i < count; i++) { + ActiveMQTempQueue queue = new ActiveMQTempQueue(id, i); + map.remove(queue, value); + Set set = map.get(queue); + assertTrue(set.isEmpty()); + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapTest.java new file mode 100644 index 0000000000..2f0f92c0a4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationMapTest.java @@ -0,0 +1,414 @@ +/** + * 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.filter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import junit.framework.TestCase; + +public class DestinationMapTest extends TestCase { + protected DestinationMap map = new DestinationMap(); + + protected ActiveMQDestination d1 = createDestination("TEST.D1"); + protected ActiveMQDestination d2 = createDestination("TEST.BAR.D2"); + protected ActiveMQDestination d3 = createDestination("TEST.BAR.D3"); + protected ActiveMQDestination compositeDestination1 = createDestination("TEST.D1,TEST.BAR.D2"); + protected ActiveMQDestination compositeDestination2 = createDestination("TEST.D1,TEST.BAR.D3"); + + protected Object v1 = "value1"; + protected Object v2 = "value2"; + protected Object v3 = "value3"; + protected Object v4 = "value4"; + protected Object v5 = "value5"; + protected Object v6 = "value6"; + + public void testCompositeDestinations() throws Exception { + ActiveMQDestination d1 = createDestination("TEST.BAR.D2"); + ActiveMQDestination d2 = createDestination("TEST.BAR.D3"); + map.put(d1, d1); + map.put(d2, d2); + map.get(createDestination("TEST.BAR.D2,TEST.BAR.D3")); + } + + public void testSimpleDestinations() throws Exception { + map.put(d1, v1); + map.put(d2, v2); + map.put(d3, v3); + + assertMapValue(d1, v1); + assertMapValue(d2, v2); + assertMapValue(d3, v3); + } + + public void testQueueAndTopicWithSameName() throws Exception { + ActiveMQQueue q1 = new ActiveMQQueue("foo"); + ActiveMQTopic t1 = new ActiveMQTopic("foo"); + + map.put(q1, v1); + map.put(t1, v2); + + assertMapValue(q1, v1); + assertMapValue(t1, v2); + } + + public void testSimpleDestinationsWithMultipleValues() throws Exception { + map.put(d1, v1); + map.put(d2, v2); + map.put(d2, v3); + + assertMapValue(d1, v1); + assertMapValue("TEST.BAR.D2", v2, v3); + assertMapValue(d3, null); + } + + public void testSimpleAndCompositeDestinations() throws Exception { + map.put(d1, v1); + map.put(compositeDestination1, v2); + map.put(compositeDestination2, v3); + + assertMapValue("TEST.D1", v1, v2, v3); + assertMapValue(d2, v2); + assertMapValue(d3, v3); + assertMapValue(compositeDestination1.toString(), v1, v2, v3); + assertMapValue(compositeDestination2.toString(), v1, v2, v3); + + map.remove(compositeDestination1, v2); + map.remove(compositeDestination2, v3); + + assertMapValue("TEST.D1", v1); + } + + public void testLookupOneStepWildcardDestinations() throws Exception { + map.put(d1, v1); + map.put(d2, v2); + map.put(d3, v3); + + assertMapValue("TEST.D1", v1); + assertMapValue("TEST.*", v1); + assertMapValue("*.D1", v1); + assertMapValue("*.*", v1); + + assertMapValue("TEST.BAR.D2", v2); + assertMapValue("TEST.*.D2", v2); + assertMapValue("*.BAR.D2", v2); + assertMapValue("*.*.D2", v2); + + assertMapValue("TEST.BAR.D3", v3); + assertMapValue("TEST.*.D3", v3); + assertMapValue("*.BAR.D3", v3); + assertMapValue("*.*.D3", v3); + + assertMapValue("TEST.BAR.D4", null); + + assertMapValue("TEST.BAR.*", v2, v3); + } + + public void testLookupMultiStepWildcardDestinations() throws Exception { + map.put(d1, v1); + map.put(d2, v2); + map.put(d3, v3); + + List allValues = Arrays.asList(new Object[] {v1, v2, v3}); + + assertMapValue(">", allValues); + assertMapValue("TEST.>", allValues); + assertMapValue("*.>", allValues); + assertMapValue("TEST.*.>", allValues); + assertMapValue("TEST.*.*.>", v2,v3); + + assertMapValue("FOO.>", null); + } + + public void testStoreWildcardWithOneStepPath() throws Exception { + put("TEST.*", v1); + put("TEST.D1", v2); + put("TEST.BAR.*", v2); + put("TEST.BAR.D3", v3); + + assertMapValue("FOO", null); + assertMapValue("TEST.FOO", v1); + assertMapValue("TEST.D1", v1, v2); + + assertMapValue("TEST.FOO.FOO", null); + assertMapValue("TEST.BAR.FOO", v2); + assertMapValue("TEST.BAR.D3", v2, v3); + + assertMapValue("TEST.*", v1, v2); + assertMapValue("*.D1", v1, v2); + assertMapValue("*.*", v1, v2); + assertMapValue("TEST.*.*", v2, v3); + assertMapValue("TEST.BAR.*", v2, v3); + assertMapValue("*.*.*", v2, v3); + assertMapValue("*.BAR.*", v2, v3); + assertMapValue("*.BAR.D3", v2, v3); + assertMapValue("*.*.D3", v2, v3); + } + + public void testStoreWildcardInMiddleOfPath() throws Exception { + put("TEST.*", v1); + put("TEST.D1", v2); + put("TEST.BAR.*", v2); + put("TEST.XYZ.D3", v3); + put("TEST.XYZ.D4", v4); + put("TEST.BAR.D3", v5); + put("TEST.*.D2", v6); + + assertMapValue("TEST.*.D3", v2, v3, v5); + assertMapValue("TEST.*.D4", v2, v4); + + assertMapValue("TEST.*", v1, v2); + assertMapValue("TEST.*.*", v2, v3, v4, v5, v6); + assertMapValue("TEST.*.>", v1, v2, v3, v4, v5, v6); + assertMapValue("TEST.>", v1, v2, v3, v4, v5, v6); + assertMapValue("TEST.>.>", v1, v2, v3, v4, v5, v6); + assertMapValue("*.*.D3", v2, v3, v5); + assertMapValue("TEST.BAR.*", v2, v5, v6); + + assertMapValue("TEST.BAR.D2", v2, v6); + assertMapValue("TEST.*.D2", v2, v6); + assertMapValue("TEST.BAR.*", v2, v5, v6); + } + + public void testDoubleWildcardDoesNotMatchLongerPattern() throws Exception { + put("TEST.*", v1); + put("TEST.BAR.D3", v2); + + assertMapValue("*.*.D3", v2); + } + + public void testWildcardAtEndOfPathAndAtBeginningOfSearch() throws Exception { + put("TEST.*", v1); + + assertMapValue("*.D1", v1); + } + + public void testAnyPathWildcardInMap() throws Exception { + put("TEST.FOO.>", v1); + + assertMapValue("TEST.FOO.BAR.WHANOT.A.B.C", v1); + assertMapValue("TEST.FOO.BAR.WHANOT", v1); + assertMapValue("TEST.FOO.BAR", v1); + + assertMapValue("TEST.*.*", v1); + assertMapValue("TEST.BAR", null); + + assertMapValue("TEST.FOO", v1); + } + + public void testSimpleAddRemove() throws Exception { + put("TEST.D1", v2); + + assertEquals("Root child count", 1, map.getTopicRootChildCount()); + + assertMapValue("TEST.D1", v2); + + remove("TEST.D1", v2); + + assertEquals("Root child count", 0, map.getTopicRootChildCount()); + assertMapValue("TEST.D1", null); + } + + public void testMQTTMappedWildcards() throws Exception { + put("TopicA", v1); + put(".TopicA", v2); + put("TopicA.", v3); + put(".", v4); + put("..TopicA", v5); + put("..", v6); + + // test wildcard patterns "#", "+", "+/#", "/+", "+/", "+/+", "+/+/", "+/+/+" + assertMapValue(">", v1, v2, v3, v4, v5, v6); + assertMapValue("*", v1); + assertMapValue("*.>", v1, v2, v3, v4, v5, v6); + assertMapValue(".*", v2, v4); + assertMapValue("*.", v3, v4); + assertMapValue("*.*", v2, v3, v4); + assertMapValue("*.*.", v6); + assertMapValue("*.*.*", v5, v6); + } + + public void testStoreAndLookupAllWildcards() throws Exception { + loadSample2(); + + assertSample2(); + + // lets remove everything and add it back + remove("TEST.FOO", v1); + + assertMapValue("TEST.FOO", v2, v3, v4); + assertMapValue("TEST.*", v2, v3, v4, v6); + assertMapValue("*.*", v2, v3, v4, v6); + + remove("TEST.XYZ", v6); + + assertMapValue("TEST.*", v2, v3, v4); + assertMapValue("*.*", v2, v3, v4); + + remove("TEST.*", v2); + + assertMapValue("TEST.*", v3, v4); + assertMapValue("*.*", v3, v4); + + remove(">", v4); + + assertMapValue("TEST.*", v3); + assertMapValue("*.*", v3); + + remove("TEST.>", v3); + remove("TEST.FOO.BAR", v5); + + assertMapValue("FOO", null); + assertMapValue("TEST.FOO", null); + assertMapValue("TEST.D1", null); + + assertMapValue("TEST.FOO.FOO", null); + assertMapValue("TEST.BAR.FOO", null); + assertMapValue("TEST.FOO.BAR", null); + assertMapValue("TEST.BAR.D3", null); + + assertMapValue("TEST.*", null); + assertMapValue("*.*", null); + assertMapValue("*.D1", null); + assertMapValue("TEST.*.*", null); + assertMapValue("TEST.BAR.*", null); + + loadSample2(); + + assertSample2(); + + remove(">", v4); + remove("TEST.*", v2); + + assertMapValue("FOO", null); + assertMapValue("TEST.FOO", v1, v3); + assertMapValue("TEST.D1", v3); + + assertMapValue("TEST.FOO.FOO", v3); + assertMapValue("TEST.BAR.FOO", v3); + assertMapValue("TEST.FOO.BAR", v3, v5); + assertMapValue("TEST.BAR.D3", v3); + + assertMapValue("TEST.*", v1, v3, v6); + assertMapValue("*.*", v1, v3, v6); + assertMapValue("*.D1", v3); + assertMapValue("TEST.*.*", v3, v5); + assertMapValue("TEST.BAR.*", v3); + } + + public void testAddAndRemove() throws Exception { + + put("FOO.A", v1); + assertMapValue("FOO.>", v1); + + put("FOO.B", v2); + assertMapValue("FOO.>", v1, v2); + + map.removeAll(createDestination("FOO.A")); + + assertMapValue("FOO.>", v2); + } + + protected void loadSample2() { + put("TEST.FOO", v1); + put("TEST.*", v2); + put("TEST.>", v3); + put(">", v4); + put("TEST.FOO.BAR", v5); + put("TEST.XYZ", v6); + } + + protected void assertSample2() { + assertMapValue("FOO", v4); + assertMapValue("TEST.FOO", v1, v2, v3, v4); + assertMapValue("TEST.D1", v2, v3, v4); + + assertMapValue("TEST.FOO.FOO", v3, v4); + assertMapValue("TEST.BAR.FOO", v3, v4); + assertMapValue("TEST.FOO.BAR", v3, v4, v5); + assertMapValue("TEST.BAR.D3", v3, v4); + + assertMapValue("TEST.*", v1, v2, v3, v4, v6); + assertMapValue("*.*", v1, v2, v3, v4, v6); + assertMapValue("*.D1", v2, v3, v4); + assertMapValue("TEST.*.*", v3, v4, v5); + assertMapValue("TEST.BAR.*", v3, v4); + } + + protected void put(String name, Object value) { + map.put(createDestination(name), value); + } + + protected void remove(String name, Object value) { + ActiveMQDestination destination = createDestination(name); + map.remove(destination, value); + } + + protected void assertMapValue(String destinationName, Object expected) { + ActiveMQDestination destination = createDestination(destinationName); + assertMapValue(destination, expected); + } + + protected void assertMapValue(String destinationName, Object expected1, Object expected2) { + assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2})); + } + + protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3) { + assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3})); + } + + protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3, Object expected4) { + assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3, expected4})); + } + + protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3, Object expected4, Object expected5) { + assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3, expected4, expected5})); + } + + protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3, Object expected4, Object expected5, Object expected6) { + assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3, expected4, expected5, expected6})); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected void assertMapValue(ActiveMQDestination destination, Object expected) { + List expectedList = null; + if (expected == null) { + expectedList = Collections.EMPTY_LIST; + } else if (expected instanceof List) { + expectedList = (List)expected; + } else { + expectedList = new ArrayList(); + expectedList.add(expected); + } + Collections.sort(expectedList); + Set actualSet = map.get(destination); + List actual = new ArrayList(actualSet); + Collections.sort(actual); + assertEquals("map value for destinationName: " + destination, expectedList, actual); + } + + protected ActiveMQDestination createDestination(String name) { + return new ActiveMQTopic(name); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationPathTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationPathTest.java new file mode 100644 index 0000000000..397cccaadf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DestinationPathTest.java @@ -0,0 +1,36 @@ +/** + * 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.filter; + +import org.apache.activemq.test.TestSupport; + +public class DestinationPathTest extends TestSupport { + + public void testPathParse() { + assertParse("FOO", new String[]{"FOO"}); + assertParse("FOO.BAR", new String[]{"FOO", "BAR"}); + assertParse("FOO.*", new String[]{"FOO", "*"}); + assertParse("FOO.>", new String[]{"FOO", ">"}); + assertParse("FOO.BAR.XYZ", new String[]{"FOO", "BAR", "XYZ"}); + assertParse("FOO.BAR.", new String[]{"FOO", "BAR", ""}); + } + + protected void assertParse(String subject, String[] expected) { + String[] path = DestinationPath.getDestinationPaths(subject); + assertArrayEqual(subject, expected, path); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicy.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicy.java new file mode 100644 index 0000000000..3dde44fdea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicy.java @@ -0,0 +1,40 @@ +/** + * 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.filter; + +import java.util.List; + +/** + * Represents a destination based policy + * + * + */ +public class DummyPolicy extends DestinationMap { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + protected Class getEntryClass() { + return DummyPolicyEntry.class; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void setEntries(List entries) { + super.setEntries(entries); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicyEntry.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicyEntry.java new file mode 100644 index 0000000000..d27158002f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicyEntry.java @@ -0,0 +1,44 @@ +/** + * 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.filter; + + +/** + * + * + */ +public class DummyPolicyEntry extends DestinationMapEntry { + + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Comparable getValue() { + return description; + } + + protected String getValuePropertyName() { + return "description"; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicyTest.java new file mode 100644 index 0000000000..5d71c54741 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/DummyPolicyTest.java @@ -0,0 +1,44 @@ +/** + * 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.filter; + +import java.util.Set; + +import org.apache.activemq.SpringTestSupport; +import org.apache.activemq.command.ActiveMQTopic; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * + */ +public class DummyPolicyTest extends SpringTestSupport { + + public void testPolicy() throws Exception { + DummyPolicy policy = (DummyPolicy)getBean("policy"); + + Set set = policy.get(new ActiveMQTopic("FOO.BAR")); + + assertSetEquals("FOO.BAR set", new Object[] {"Edam", "Cheddar"}, set); + } + + @Override + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/filter/dummyPolicy.xml"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/dummyPolicy.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/dummyPolicy.xml new file mode 100644 index 0000000000..65859861b6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/filter/dummyPolicy.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jmx/JmxCreateNCTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jmx/JmxCreateNCTest.java new file mode 100644 index 0000000000..e96c5967ad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jmx/JmxCreateNCTest.java @@ -0,0 +1,67 @@ +/** + * 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.jmx; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerViewMBean; +import org.apache.activemq.broker.jmx.NetworkConnectorViewMBean; +import org.junit.Test; + +import javax.management.ObjectName; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * This test shows that when we create a network connector via JMX, + * the NC/bridge shows up in the MBean Server + * + * @author Christian Posta + */ +public class JmxCreateNCTest { + + private static final String BROKER_NAME = "jmx-broker"; + + @Test + public void testBridgeRegistration() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName(BROKER_NAME); + broker.setUseJmx(true); // explicitly set this so no funny issues + broker.start(); + broker.waitUntilStarted(); + + // now create network connector over JMX + ObjectName brokerObjectName = new ObjectName("org.apache.activemq:type=Broker,brokerName=" + BROKER_NAME); + BrokerViewMBean proxy = (BrokerViewMBean) broker.getManagementContext().newProxyInstance(brokerObjectName, + BrokerViewMBean.class, true); + + assertNotNull("We could not retrieve the broker from JMX", proxy); + + // let's add the NC + String connectoName = proxy.addNetworkConnector("static:(tcp://localhost:61617)"); + assertEquals("NC", connectoName); + + // Make sure we can retrieve the NC through JMX + ObjectName networkConnectorObjectName = new ObjectName("org.apache.activemq:type=Broker,brokerName=" + BROKER_NAME + + ",connector=networkConnectors,networkConnectorName=" + connectoName); + NetworkConnectorViewMBean nc = (NetworkConnectorViewMBean) broker.getManagementContext().newProxyInstance(networkConnectorObjectName, + NetworkConnectorViewMBean.class, true); + + assertNotNull(nc); + assertEquals("NC", nc.getName()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jmx/OpenTypeSupportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jmx/OpenTypeSupportTest.java new file mode 100644 index 0000000000..7306dfd6f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jmx/OpenTypeSupportTest.java @@ -0,0 +1,115 @@ +/** + * 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.jmx; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.CompositeDataConstants; +import org.apache.activemq.broker.jmx.OpenTypeSupport; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.command.ActiveMQBytesMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; + +public class OpenTypeSupportTest { + private static final Logger LOG = LoggerFactory.getLogger(OpenTypeSupportTest.class); + + private static BrokerService brokerService; + private static String TESTQUEUE = "testQueue"; + private static ActiveMQConnectionFactory connectionFactory; + private static String BYTESMESSAGE_TEXT = "This is a short text"; + private static String BROKER_ADDRESS = "tcp://localhost:0"; + private static ActiveMQQueue queue = new ActiveMQQueue(TESTQUEUE); + + private String connectionUri; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + connectionUri = brokerService.addConnector(BROKER_ADDRESS).getPublishableConnectString(); + brokerService.start(); + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + sendMessage(); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + private static void sendMessage() throws JMSException { + Connection conn = connectionFactory.createConnection(); + try { + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination queue = session.createQueue(TESTQUEUE); + BytesMessage toSend = session.createBytesMessage(); + toSend.writeBytes(BYTESMESSAGE_TEXT.getBytes()); + MessageProducer producer = session.createProducer(queue); + producer.send(queue, toSend); + } finally { + conn.close(); + } + } + + @Test + public void bytesMessagePreview() throws Exception { + QueueViewMBean queue = getProxyToQueueViewMBean(); + assertEquals(extractText(queue.browse()[0]), extractText(queue.browse()[0])); + } + + @Test + public void testBrowseByteMessageFails() throws Exception { + ActiveMQBytesMessage bm = new ActiveMQBytesMessage(); + bm.writeBytes("123456".getBytes()); + Object result = OpenTypeSupport.convert(bm); + LOG.info("result : " + result); + } + + private String extractText(CompositeData message) { + Byte content[] = (Byte[]) message.get(CompositeDataConstants.BODY_PREVIEW); + byte out[] = new byte[content.length]; + for (int i = 0; i < content.length; i++) { + out[i] = content[i]; + } + return new String(out); + } + + private QueueViewMBean getProxyToQueueViewMBean() throws MalformedObjectNameException, JMSException { + final ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queue.getQueueName()); + QueueViewMBean proxy = (QueueViewMBean) + brokerService.getManagementContext().newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true); + return proxy; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ActiveMQInitialContextFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ActiveMQInitialContextFactoryTest.java new file mode 100644 index 0000000000..86e5a43939 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ActiveMQInitialContextFactoryTest.java @@ -0,0 +1,75 @@ +/** + * 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.jndi; + +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +/** + * + */ +public class ActiveMQInitialContextFactoryTest extends JNDITestSupport { + + public void testConnectionFactoriesArePresent() throws NamingException { + String lookupName = getConnectionFactoryLookupName(); + assertConnectionFactoryPresent(lookupName); + } + + public void testDestinationsArePresent() throws NamingException { + + // Retrieving destinations context is not yet implemented on the broker. + // For this test, a jndi file properties will be used. + + InitialContext context = new InitialContext(); + + // make sure context is not null + assertTrue("Created context", context != null); + + Object topicDestination = context.lookup("MyTopic"); + + // check if MyTopic is an ActiveMQTopic + assertTrue("Should have found a topic but found: " + topicDestination, topicDestination instanceof ActiveMQTopic); + + Object queueDestination = context.lookup("MyQueue"); + + // check if MyQueue is an ActiveMQueue + assertTrue("Should have found a queue but found: " + queueDestination, queueDestination instanceof ActiveMQQueue); + + } + + public void testDynamicallyGrowing() throws Exception { + Object answer = context.lookup("dynamicQueues/FOO.BAR"); + assertTrue("Should have found a queue but found: " + answer, answer instanceof ActiveMQQueue); + + ActiveMQQueue queue = (ActiveMQQueue)answer; + assertEquals("queue name", "FOO.BAR", queue.getPhysicalName()); + + answer = context.lookup("dynamicTopics/A.B.C"); + assertTrue("Should have found a topic but found: " + answer, answer instanceof ActiveMQTopic); + + ActiveMQTopic topic = (ActiveMQTopic)answer; + assertEquals("topic name", "A.B.C", topic.getPhysicalName()); + + } + + protected String getConnectionFactoryLookupName() { + return "ConnectionFactory"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ActiveMQWASInitialContextFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ActiveMQWASInitialContextFactoryTest.java new file mode 100644 index 0000000000..f9ce5b1903 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ActiveMQWASInitialContextFactoryTest.java @@ -0,0 +1,43 @@ +/** + * 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.jndi; + +import java.util.Hashtable; + +import javax.naming.Context; + +public class ActiveMQWASInitialContextFactoryTest extends JNDITestSupport { + + @SuppressWarnings("unchecked") + public void testTransformEnvironment() { + Hashtable originalEnvironment = new Hashtable(); + originalEnvironment.put("java.naming.connectionFactoryNames", "ConnectionFactory"); + originalEnvironment.put("java.naming.topic.jms.systemMessageTopic", "jms/systemMessageTopic"); + originalEnvironment.put(Context.PROVIDER_URL, "tcp://localhost:61616;tcp://localhost:61617"); + originalEnvironment.put("non-string", Integer.valueOf(43)); + originalEnvironment.put("java.naming.queue", "jms/systemMessageQueue"); + + Hashtable transformedEnvironment = new ActiveMQWASInitialContextFactory().transformEnvironment(originalEnvironment); + assertEquals("ConnectionFactory", "ConnectionFactory", transformedEnvironment.get("connectionFactoryNames")); + assertEquals("topic.jm", "jms/systemMessageTopic", transformedEnvironment.get("topic.jms/systemMessageTopic")); + assertEquals("java.naming.provider.url", "tcp://localhost:61616,tcp://localhost:61617", transformedEnvironment.get("java.naming.provider.url")); + assertNull("non-string", transformedEnvironment.get("non-string")); + + assertEquals("queue", "jms/systemMessageQueue", transformedEnvironment.get("java.naming.queue")); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/CustomConnectionFactoryNameTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/CustomConnectionFactoryNameTest.java new file mode 100644 index 0000000000..517735b855 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/CustomConnectionFactoryNameTest.java @@ -0,0 +1,56 @@ +/** + * 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.jndi; + +import javax.naming.NamingException; + +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * Test case for AMQ-141 + * + * + */ +public class CustomConnectionFactoryNameTest extends ActiveMQInitialContextFactoryTest { + + @Override + public void testConnectionFactoriesArePresent() throws NamingException { + super.testConnectionFactoriesArePresent(); + assertConnectionFactoryPresent("jms/Connection"); + assertConnectionFactoryPresent("jms/DURABLE_SUB_CONNECTION_FACTORY"); + } + + public void testConnectionFactoriesAreConfigured() throws NamingException { + super.testConnectionFactoriesArePresent(); + ActiveMQConnectionFactory factory1 = (ActiveMQConnectionFactory) context.lookup("jms/Connection"); + assertNull(factory1.getClientID()); + ActiveMQConnectionFactory factory2 = (ActiveMQConnectionFactory) context.lookup("jms/DURABLE_SUB_CONNECTION_FACTORY"); + assertEquals("testclient", factory2.getClientID()); + } + + @Override + protected String getConnectionFactoryLookupName() { + return "myConnectionFactory"; + } + + @Override + protected void configureEnvironment() { + super.configureEnvironment(); + environment.put("connectionFactoryNames", " myConnectionFactory, jms/Connection, jms/DURABLE_SUB_CONNECTION_FACTORY"); + environment.put("connection.jms/DURABLE_SUB_CONNECTION_FACTORY.clientID", "testclient"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/DestinationNameWithSlashTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/DestinationNameWithSlashTest.java new file mode 100644 index 0000000000..6e3e9da76e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/DestinationNameWithSlashTest.java @@ -0,0 +1,36 @@ +/** + * 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.jndi; + + +/** + * Test case for AMQ-140 + * + * + */ +public class DestinationNameWithSlashTest extends JNDITestSupport { + public void testNameWithSlash() throws Exception { + assertDestinationExists("jms/Queue"); + + } + + @Override + protected void configureEnvironment() { + super.configureEnvironment(); + environment.put("queue.jms/Queue", "example.myqueue"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/InitialContextTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/InitialContextTest.java new file mode 100644 index 0000000000..2c983a5a36 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/InitialContextTest.java @@ -0,0 +1,97 @@ +/** + * 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.jndi; + +import java.util.Properties; + +import javax.naming.Context; +import javax.naming.InitialContext; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQXAConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class InitialContextTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(InitialContextTest.class); + + public void testInitialContext() throws Exception { + InitialContext context = new InitialContext(); + assertTrue("Created context", context != null); + + ActiveMQConnectionFactory connectionFactory = (ActiveMQConnectionFactory)context.lookup("ConnectionFactory"); + + assertTrue("Should have created a ConnectionFactory", connectionFactory != null); + + LOG.info("Created with brokerURL: " + connectionFactory.getBrokerURL()); + + } + + public void testInitialContextHasXA() throws Exception { + InitialContext context = new InitialContext(); + assertTrue("Created context", context != null); + + ActiveMQXAConnectionFactory connectionFactory = (ActiveMQXAConnectionFactory)context.lookup("XAConnectionFactory"); + + assertTrue("Should have created an XAConnectionFactory", connectionFactory != null); + + LOG.info("Created with brokerURL: " + connectionFactory.getBrokerURL()); + + } + + public void testUsingStandardJNDIKeys() throws Exception { + Properties properties = new Properties(); + properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + String expected = "tcp://localhost:65432"; + properties.put(Context.PROVIDER_URL, expected); + + InitialContext context = new InitialContext(properties); + assertTrue("Created context", context != null); + + ActiveMQConnectionFactory connectionFactory = (ActiveMQConnectionFactory)context.lookup("ConnectionFactory"); + + assertTrue("Should have created a ConnectionFactory", connectionFactory != null); + + assertEquals("the brokerURL should match", expected, connectionFactory.getBrokerURL()); + } + + public void testConnectionFactoryPolicyConfig() throws Exception { + + Properties properties = new Properties(); + properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory"); + properties.put(Context.PROVIDER_URL, "tcp://localhost:65432"); + properties.put("prefetchPolicy.queuePrefetch", "777"); + properties.put("redeliveryPolicy.maximumRedeliveries", "15"); + properties.put("redeliveryPolicy.backOffMultiplier", "32"); + + InitialContext context = new InitialContext(properties); + assertTrue("Created context", context != null); + + ActiveMQConnectionFactory connectionFactory = (ActiveMQConnectionFactory)context.lookup("ConnectionFactory"); + + assertTrue("Should have created a ConnectionFactory", connectionFactory != null); + + assertEquals(777, connectionFactory.getPrefetchPolicy().getQueuePrefetch()); + assertEquals(15, connectionFactory.getRedeliveryPolicy().getMaximumRedeliveries()); + assertEquals(32d, connectionFactory.getRedeliveryPolicy().getBackOffMultiplier()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/JNDITestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/JNDITestSupport.java new file mode 100644 index 0000000000..13adbc458d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/JNDITestSupport.java @@ -0,0 +1,103 @@ +/** + * 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.jndi; + +import java.util.Hashtable; + +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * + */ +public abstract class JNDITestSupport extends TestCase { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(JNDITestSupport.class); + + protected Hashtable environment = new Hashtable(); + protected Context context; + + protected void assertConnectionFactoryPresent(String lookupName) throws NamingException { + Object connectionFactory = context.lookup(lookupName); + + assertTrue("Should have created a ConnectionFactory for key: " + lookupName + + " but got: " + connectionFactory, connectionFactory instanceof ConnectionFactory); + } + + protected void assertBinding(Binding binding) throws NamingException { + Object object = binding.getObject(); + assertTrue("Should have got a child context but got: " + object, object instanceof Context); + + Context childContext = (Context) object; + NamingEnumeration iter = childContext.listBindings(""); + while (iter.hasMore()) { + Binding destinationBinding = iter.next(); + LOG.info("Found destination: " + destinationBinding.getName()); + Object destination = destinationBinding.getObject(); + assertTrue("Should have a Destination but got: " + destination, destination instanceof Destination); + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + configureEnvironment(); + + InitialContextFactory factory = new ActiveMQInitialContextFactory(); + context = factory.getInitialContext(environment); + assertTrue("No context created", context != null); + } + + /** + * Stops all existing ActiveMQConnectionFactory in Context. + * + * @throws javax.naming.NamingException + */ + @Override + protected void tearDown() throws NamingException, JMSException { + NamingEnumeration iter = context.listBindings(""); + while (iter.hasMore()) { + Binding binding = iter.next(); + Object connFactory = binding.getObject(); + if (connFactory instanceof ActiveMQConnectionFactory) { + // ((ActiveMQConnectionFactory) connFactory).stop(); + } + } + } + + protected void configureEnvironment() { + environment.put("brokerURL", "vm://localhost"); + } + + protected void assertDestinationExists(String name) throws NamingException { + Object object = context.lookup(name); + assertTrue("Should have received a Destination for name: " + name + " but instead found: " + object, + object instanceof Destination); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ObjectFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ObjectFactoryTest.java new file mode 100644 index 0000000000..c3891448b1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/ObjectFactoryTest.java @@ -0,0 +1,89 @@ +/** + * 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.jndi; + +import javax.naming.Reference; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; + +public class ObjectFactoryTest extends CombinationTestSupport { + public void testConnectionFactory() throws Exception { + // Create sample connection factory + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(); + factory.setDispatchAsync(true); + factory.setBrokerURL("vm://test"); + factory.setClientID("test"); + factory.setCopyMessageOnSend(false); + factory.setDisableTimeStampsByDefault(true); + factory.setObjectMessageSerializationDefered(true); + factory.setOptimizedMessageDispatch(false); + factory.setPassword("pass"); + factory.setUseAsyncSend(true); + factory.setUseCompression(true); + factory.setUseRetroactiveConsumer(true); + factory.setUserName("user"); + factory.getPrefetchPolicy().setQueuePrefetch(777); + factory.getRedeliveryPolicy().setMaximumRedeliveries(15); + factory.getRedeliveryPolicy().setBackOffMultiplier((short) 32); + + + // Create reference + Reference ref = JNDIReferenceFactory.createReference(factory.getClass().getName(), factory); + + // Get object created based on reference + ActiveMQConnectionFactory temp; + JNDIReferenceFactory refFactory = new JNDIReferenceFactory(); + temp = (ActiveMQConnectionFactory)refFactory.getObjectInstance(ref, null, null, null); + + // Check settings + assertEquals(factory.isDispatchAsync(), temp.isDispatchAsync()); + assertEquals(factory.getBrokerURL(), temp.getBrokerURL()); + assertEquals(factory.getClientID(), temp.getClientID()); + assertEquals(factory.isCopyMessageOnSend(), temp.isCopyMessageOnSend()); + assertEquals(factory.isDisableTimeStampsByDefault(), temp.isDisableTimeStampsByDefault()); + assertEquals(factory.isObjectMessageSerializationDefered(), temp.isObjectMessageSerializationDefered()); + assertEquals(factory.isOptimizedMessageDispatch(), temp.isOptimizedMessageDispatch()); + assertEquals(factory.getPassword(), temp.getPassword()); + assertEquals(factory.isUseAsyncSend(), temp.isUseAsyncSend()); + assertEquals(factory.isUseCompression(), temp.isUseCompression()); + assertEquals(factory.isUseRetroactiveConsumer(), temp.isUseRetroactiveConsumer()); + assertEquals(factory.getUserName(), temp.getUserName()); + assertEquals(factory.getPrefetchPolicy().getQueuePrefetch(), temp.getPrefetchPolicy().getQueuePrefetch()); + assertEquals(factory.getRedeliveryPolicy().getMaximumRedeliveries(), temp.getRedeliveryPolicy().getMaximumRedeliveries()); + assertEquals(factory.getRedeliveryPolicy().getBackOffMultiplier(), temp.getRedeliveryPolicy().getBackOffMultiplier()); + } + + public void testDestination() throws Exception { + // Create sample destination + ActiveMQDestination dest = new ActiveMQQueue(); + dest.setPhysicalName("TEST.FOO"); + + // Create reference + Reference ref = JNDIReferenceFactory.createReference(dest.getClass().getName(), dest); + + // Get object created based on reference + ActiveMQDestination temp; + JNDIReferenceFactory refFactory = new JNDIReferenceFactory(); + temp = (ActiveMQDestination)refFactory.getObjectInstance(ref, null, null, null); + + // Check settings + assertEquals(dest.getPhysicalName(), temp.getPhysicalName()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/XAConnectionFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/XAConnectionFactoryTest.java new file mode 100644 index 0000000000..cf7cca1707 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/jndi/XAConnectionFactoryTest.java @@ -0,0 +1,32 @@ +/** + * 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.jndi; + +import javax.jms.XAConnectionFactory; +import javax.naming.NamingException; + +public class XAConnectionFactoryTest extends ActiveMQInitialContextFactoryTest { + + public void testConnectionFactoriesIsXA() throws NamingException { + assertTrue("connection factory implements XA", context.lookup(getConnectionFactoryLookupName()) instanceof XAConnectionFactory); + } + + protected void configureEnvironment() { + environment.put("xa", "true"); + super.configureEnvironment(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/joramtests/ActiveMQAdmin.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/joramtests/ActiveMQAdmin.java new file mode 100644 index 0000000000..b20b9adf46 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/joramtests/ActiveMQAdmin.java @@ -0,0 +1,150 @@ +/** + * 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.joramtests; + +import java.io.File; +import java.net.URI; +import java.util.Hashtable; + +import javax.jms.ConnectionFactory; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.objectweb.jtests.jms.admin.Admin; + +/** + * + * @author Hiram Chirino + */ +public class ActiveMQAdmin implements Admin { + + Context context; + { + try { + // Use the jetty JNDI context since it's mutable. + final Hashtable env = new Hashtable(); + env.put("java.naming.factory.initial", "org.eclipse.jetty.jndi.InitialContextFactory"); + env.put("java.naming.factory.url.pkgs", "org.eclipse.jetty.jndi");; + context = new InitialContext(env); + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + protected BrokerService createBroker() throws Exception { + return BrokerFactory.createBroker(new URI("broker://()/localhost?persistent=false")); + } + + public String getName() { + return getClass().getName(); + } + + BrokerService broker; + public void startServer() throws Exception { + if (System.getProperty("basedir") == null) { + File file = new File("."); + System.setProperty("basedir", file.getAbsolutePath()); + } + broker = createBroker(); + broker.start(); + } + + public void stopServer() throws Exception { + broker.stop(); + } + + public void start() throws Exception { + } + + public void stop() throws Exception { + } + + public Context createContext() throws NamingException { + return context; + } + + public void createQueue(String name) { + try { + context.bind(name, new ActiveMQQueue(name)); + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + public void createTopic(String name) { + try { + context.bind(name, new ActiveMQTopic(name)); + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + public void deleteQueue(String name) { + // BrokerTestSupport.delete_queue((Broker)base.broker, name); + try { + context.unbind(name); + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + public void deleteTopic(String name) { + try { + context.unbind(name); + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + public void createConnectionFactory(String name) { + try { + final ConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + ((ActiveMQConnectionFactory) factory).setNestedMapAndListEnabled(false); + context.bind(name, factory); + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + public void deleteConnectionFactory(String name) { + try { + context.unbind(name); + } catch (NamingException e) { + throw new RuntimeException(e); + } + } + + public void createQueueConnectionFactory(String name) { + createConnectionFactory(name); + } + public void createTopicConnectionFactory(String name) { + createConnectionFactory(name); + } + public void deleteQueueConnectionFactory(String name) { + deleteConnectionFactory(name); + } + public void deleteTopicConnectionFactory(String name) { + deleteConnectionFactory(name); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/joramtests/JoramJmsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/joramtests/JoramJmsTest.java new file mode 100644 index 0000000000..00c5423a72 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/joramtests/JoramJmsTest.java @@ -0,0 +1,74 @@ +/** + * 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.joramtests; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.objectweb.jtests.jms.conform.connection.ConnectionTest; +import org.objectweb.jtests.jms.conform.connection.TopicConnectionTest; +import org.objectweb.jtests.jms.conform.message.MessageBodyTest; +import org.objectweb.jtests.jms.conform.message.MessageDefaultTest; +import org.objectweb.jtests.jms.conform.message.MessageTypeTest; +import org.objectweb.jtests.jms.conform.message.headers.MessageHeaderTest; +import org.objectweb.jtests.jms.conform.message.properties.JMSXPropertyTest; +import org.objectweb.jtests.jms.conform.message.properties.MessagePropertyConversionTest; +import org.objectweb.jtests.jms.conform.message.properties.MessagePropertyTest; +import org.objectweb.jtests.jms.conform.queue.QueueBrowserTest; +import org.objectweb.jtests.jms.conform.queue.TemporaryQueueTest; +import org.objectweb.jtests.jms.conform.selector.SelectorSyntaxTest; +import org.objectweb.jtests.jms.conform.selector.SelectorTest; +import org.objectweb.jtests.jms.conform.session.QueueSessionTest; +import org.objectweb.jtests.jms.conform.session.SessionTest; +import org.objectweb.jtests.jms.conform.session.TopicSessionTest; +import org.objectweb.jtests.jms.conform.session.UnifiedSessionTest; +import org.objectweb.jtests.jms.conform.topic.TemporaryTopicTest; + +/** + * @author Hiram Chirino + */ +public class JoramJmsTest extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTestSuite(SelectorTest.class); + suite.addTestSuite(ConnectionTest.class); + suite.addTestSuite(TopicConnectionTest.class); + suite.addTestSuite(MessageHeaderTest.class); + suite.addTestSuite(MessageBodyTest.class); + suite.addTestSuite(MessageDefaultTest.class); + suite.addTestSuite(MessageTypeTest.class); + suite.addTestSuite(JMSXPropertyTest.class); + suite.addTestSuite(MessagePropertyConversionTest.class); + suite.addTestSuite(TemporaryQueueTest.class); + suite.addTestSuite(SelectorSyntaxTest.class); + suite.addTestSuite(QueueSessionTest.class); + suite.addTestSuite(SessionTest.class); + suite.addTestSuite(TopicSessionTest.class); + suite.addTestSuite(TemporaryTopicTest.class); + suite.addTestSuite(UnifiedSessionTest.class); + suite.addTestSuite(QueueBrowserTest.class); + suite.addTestSuite(MessagePropertyTest.class); + return suite; + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/leveldb/LevelDBStoreBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/leveldb/LevelDBStoreBrokerTest.java new file mode 100644 index 0000000000..6f58586c8c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/leveldb/LevelDBStoreBrokerTest.java @@ -0,0 +1,62 @@ +/** + * 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.leveldb; + +import junit.framework.Test; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTest; +import org.apache.activemq.store.PersistenceAdapter; + +import java.io.File; +import java.io.IOException; + +/** + * @author Hiram Chirino + */ +public class LevelDBStoreBrokerTest extends BrokerTest { + + public static Test suite() { + return suite(LevelDBStoreBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistenceAdapter(createPersistenceAdapter(true)); + return broker; + } + + protected PersistenceAdapter createPersistenceAdapter(boolean delete) { + LevelDBStore store = new LevelDBStore(); + store.setDirectory(new File("target/activemq-data/leveldb")); + if (delete) { + store.deleteAllMessages(); + } + return store; + } + + protected BrokerService createRestartedBroker() throws IOException { + BrokerService broker = new BrokerService(); + broker.setPersistenceAdapter(createPersistenceAdapter(false)); + return broker; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/leveldb/LevelDBXARecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/leveldb/LevelDBXARecoveryBrokerTest.java new file mode 100644 index 0000000000..82cd7e4561 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/leveldb/LevelDBXARecoveryBrokerTest.java @@ -0,0 +1,68 @@ +/** + * 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.leveldb; + +import java.io.File; +import java.io.IOException; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.XARecoveryBrokerTest; +import org.apache.commons.io.FileUtils; + +/** + * @author Hiram Chirino + */ +public class LevelDBXARecoveryBrokerTest extends XARecoveryBrokerTest { + public static final String LEVELDB_DIR_BASE = "target/activemq-data/xahaleveldb"; + public static String levelDbDirectoryName; + + @Override + protected void setUp() throws Exception { + levelDbDirectoryName = LEVELDB_DIR_BASE + "/" + System.currentTimeMillis(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + try { + File levelDbDir = new File(levelDbDirectoryName); + FileUtils.deleteDirectory(levelDbDir); + } catch (IOException e) { + } + } + + + public static Test suite() { + return suite(LevelDBXARecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + protected void configureBroker(BrokerService broker) throws Exception { + super.configureBroker(broker); + LevelDBStore store = new LevelDBStore(); + store.setDirectory(new File(levelDbDirectoryName)); + broker.setPersistenceAdapter(store); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadClient.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadClient.java new file mode 100644 index 0000000000..0f69567c62 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadClient.java @@ -0,0 +1,233 @@ +/** + * 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.load; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQMessageAudit; +import org.apache.activemq.perf.PerfRate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class LoadClient implements Runnable{ + private static final Logger LOG = LoggerFactory.getLogger(LoadClient.class); + protected static int SLEEP_TIME = 2; + protected String name; + protected ConnectionFactory factory; + protected Connection connection; + protected Destination startDestination; + protected Destination nextDestination; + protected Session session; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected PerfRate rate = new PerfRate(); + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected ActiveMQMessageAudit audit = new ActiveMQMessageAudit(); + protected boolean connectionPerMessage = false; + protected boolean running; + protected int timeout = 10000; + + + public LoadClient(String name,ConnectionFactory factory) { + this.name=name; + this.factory = factory; + } + + + + public synchronized void start() throws JMSException { + if (!running) { + rate.reset(); + running = true; + if (!connectionPerMessage) { + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(getConsumeDestination()); + producer = session.createProducer(getSendDestination()); + producer.setDeliveryMode(this.deliveryMode); + + } + + Thread t = new Thread(this); + t.setName(name); + t.start(); + } + } + + public void stop() throws JMSException, InterruptedException { + running = false; + if(connection != null) { + connection.stop(); + } + } + + + public void run() { + try { + while (running) { + String result = consume(); + if(result != null) { + send(result); + rate.increment(); + } + else if (running) { + LOG.error(name + " Failed to consume!"); + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + protected String consume() throws Exception { + Connection con = null; + MessageConsumer c = consumer; + if (connectionPerMessage){ + con = factory.createConnection(); + con.start(); + Session s = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + c = s.createConsumer(getConsumeDestination()); + } + TextMessage result = (TextMessage) c.receive(timeout); + if (result != null) { + if (audit.isDuplicate(result.getJMSMessageID())) { + throw new JMSException("Received duplicate " + result.getText()); + } + if (!audit.isInOrder(result.getJMSMessageID())) { + throw new JMSException("Out of order " + result.getText()); + } + + if (connectionPerMessage) { + Thread.sleep(SLEEP_TIME);//give the broker a chance + con.close(); + } + } + return result != null ? result.getText() : null; + } + + protected void send(String text) throws Exception { + Connection con = connection; + MessageProducer p = producer; + Session s = session; + if (connectionPerMessage){ + con = factory.createConnection(); + con.start(); + s = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + p = s.createProducer(getSendDestination()); + p.setDeliveryMode(deliveryMode); + } + TextMessage message = s.createTextMessage(text); + p.send(message); + if (connectionPerMessage) { + Thread.sleep(SLEEP_TIME);//give the broker a chance + con.close(); + } + } + + + + public String getName() { + return name; + } + + + + public void setName(String name) { + this.name = name; + } + + + + public Destination getStartDestination() { + return startDestination; + } + + + + public void setStartDestination(Destination startDestination) { + this.startDestination = startDestination; + } + + + + public Destination getNextDestination() { + return nextDestination; + } + + + + public void setNextDestination(Destination nextDestination) { + this.nextDestination = nextDestination; + } + + + + public int getDeliveryMode() { + return deliveryMode; + } + + + + public void setDeliveryMode(int deliveryMode) { + this.deliveryMode = deliveryMode; + } + + + + public boolean isConnectionPerMessage() { + return connectionPerMessage; + } + + + + public void setConnectionPerMessage(boolean connectionPerMessage) { + this.connectionPerMessage = connectionPerMessage; + } + + + + public int getTimeout() { + return timeout; + } + + + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + protected Destination getSendDestination() { + return nextDestination; + } + + protected Destination getConsumeDestination() { + return startDestination; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadController.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadController.java new file mode 100644 index 0000000000..22b90642f5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadController.java @@ -0,0 +1,103 @@ +/** + * 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.load; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; + +/** + * + */ +public class LoadController extends LoadClient{ + + private int numberOfBatches=1; + private int batchSize =1000; + private int count; + private final CountDownLatch stopped = new CountDownLatch(1); + + public LoadController(String name,ConnectionFactory factory) { + super(name,factory); + } + + + public int awaitTestComplete() throws InterruptedException { + stopped.await(60*5,TimeUnit.SECONDS); + return count; + } + + @Override + public void stop() throws JMSException, InterruptedException { + running = false; + stopped.countDown(); + if (connection != null) { + this.connection.stop(); + } + } + + @Override + public void run() { + try { + for (int i = 0; i < numberOfBatches; i++) { + for (int j = 0; j < batchSize; j++) { + String payLoad = "batch[" + i + "]no:" + j; + send(payLoad); + } + for (int j = 0; j < batchSize; j++) { + String result = consume(); + if (result != null) { + count++; + rate.increment(); + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + } finally { + stopped.countDown(); + } + } + + public int getNumberOfBatches() { + return numberOfBatches; + } + + public void setNumberOfBatches(int numberOfBatches) { + this.numberOfBatches = numberOfBatches; + } + + public int getBatchSize() { + return batchSize; + } + + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + } + + @Override + protected Destination getSendDestination() { + return startDestination; + } + + @Override + protected Destination getConsumeDestination() { + return nextDestination; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadTest.java new file mode 100644 index 0000000000..ee1037b54a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/load/LoadTest.java @@ -0,0 +1,155 @@ +/** + * 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.load; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class LoadTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(LoadTest.class); + + protected BrokerService broker; + protected String bindAddress="tcp://localhost:61616"; + + protected LoadController controller; + protected LoadClient[] clients; + protected ConnectionFactory factory; + protected Destination destination; + protected int numberOfClients = 50; + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected int batchSize = 1000; + protected int numberOfBatches = 10; + protected int timeout = Integer.MAX_VALUE; + protected boolean connectionPerMessage = false; + protected Connection managementConnection; + protected Session managementSession; + + /** + * Sets up a test where the producer and consumer have their own connection. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(bindAddress); + } + factory = createConnectionFactory(bindAddress); + managementConnection = factory.createConnection(); + managementSession = managementConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Destination startDestination = createDestination(managementSession, getClass()+".start"); + Destination endDestination = createDestination(managementSession, getClass()+".end"); + LOG.info("Running with " + numberOfClients + " clients - sending " + + numberOfBatches + " batches of " + batchSize + " messages"); + controller = new LoadController("Controller",factory); + controller.setBatchSize(batchSize); + controller.setNumberOfBatches(numberOfBatches); + controller.setDeliveryMode(deliveryMode); + controller.setConnectionPerMessage(connectionPerMessage); + controller.setStartDestination(startDestination); + controller.setNextDestination(endDestination); + controller.setTimeout(timeout); + clients = new LoadClient[numberOfClients]; + for (int i = 0; i < numberOfClients; i++) { + Destination inDestination = null; + if (i==0) { + inDestination = startDestination; + }else { + inDestination = createDestination(managementSession, getClass() + ".client."+(i)); + } + Destination outDestination = null; + if (i==(numberOfClients-1)) { + outDestination = endDestination; + }else { + outDestination = createDestination(managementSession, getClass() + ".client."+(i+1)); + } + LoadClient client = new LoadClient("client("+i+")",factory); + client.setTimeout(timeout); + client.setDeliveryMode(deliveryMode); + client.setConnectionPerMessage(connectionPerMessage); + client.setStartDestination(inDestination); + client.setNextDestination(outDestination); + clients[i] = client; + } + + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + managementConnection.close(); + for (int i = 0; i < numberOfClients; i++) { + clients[i].stop(); + } + controller.stop(); + if (broker != null) { + broker.stop(); + broker = null; + } + } + + protected Destination createDestination(Session s, String destinationName) throws JMSException { + return s.createQueue(destinationName); + } + + /** + * Factory method to create a new broker + * + * @throws Exception + */ + protected BrokerService createBroker(String uri) throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer,uri); + answer.start(); + return answer; + } + + + + protected void configureBroker(BrokerService answer,String uri) throws Exception { + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(uri); + answer.setUseShutdownHook(false); + } + + protected ActiveMQConnectionFactory createConnectionFactory(String uri) throws Exception { + return new ActiveMQConnectionFactory(uri); + } + + public void testLoad() throws JMSException, InterruptedException { + for (int i = 0; i < numberOfClients; i++) { + clients[i].start(); + } + controller.start(); + assertEquals((batchSize* numberOfBatches),controller.awaitTestComplete()); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/BoundaryStatisticTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/BoundaryStatisticTest.java new file mode 100644 index 0000000000..194cbbcf11 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/BoundaryStatisticTest.java @@ -0,0 +1,38 @@ +/** + * 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.management; + + +public class BoundaryStatisticTest extends StatisticTestSupport { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(BoundaryStatisticTest.class); + + /** + * Use case for BoundaryStatisticImpl class. + * @throws Exception + */ + public void testStatistic() throws Exception { + BoundaryStatisticImpl stat = new BoundaryStatisticImpl("myBoundaryStat", "seconds", "myBoundaryStatDesc", 1000, 2000); + assertStatistic(stat, "myBoundaryStat", "seconds", "myBoundaryStatDesc"); + + assertEquals(1000, stat.getLowerBound()); + assertEquals(2000, stat.getUpperBound()); + + LOG.info("Stat is: " + stat); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/BoundedRangeStatisticTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/BoundedRangeStatisticTest.java new file mode 100644 index 0000000000..b920718c75 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/BoundedRangeStatisticTest.java @@ -0,0 +1,38 @@ +/** + * 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.management; + + + +/** + * + */ +public class BoundedRangeStatisticTest extends RangeStatisticTest { + + /** + * Use case for BoundedRangeStatisticImpl class. + * @throws Exception + */ + public void testStatistic() throws Exception { + BoundedRangeStatisticImpl stat = new BoundedRangeStatisticImpl("myRange", "millis", "myDescription", 10, 3000); + assertStatistic(stat, "myRange", "millis", "myDescription"); + assertEquals(10, stat.getLowerBound()); + assertEquals(3000, stat.getUpperBound()); + + assertRangeStatistic(stat); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/CountStatisticTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/CountStatisticTest.java new file mode 100644 index 0000000000..85f8be104d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/CountStatisticTest.java @@ -0,0 +1,57 @@ +/** + * 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.management; + + +public class CountStatisticTest extends StatisticTestSupport { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(CountStatisticTest.class); + + /** + * Use case for CountStatisticImple class. + * @throws Exception + */ + public void testStatistic() throws Exception { + CountStatisticImpl stat = new CountStatisticImpl("myCounter", "seconds", "myDescription"); + stat.setEnabled(true); + assertStatistic(stat, "myCounter", "seconds", "myDescription"); + + assertEquals(0, stat.getCount()); + + stat.increment(); + assertEquals(1, stat.getCount()); + + stat.increment(); + assertEquals(2, stat.getCount()); + + stat.decrement(); + assertEquals(1, stat.getCount()); + + Thread.sleep(500); + + stat.increment(); + + assertLastTimeNotStartTime(stat); + + LOG.info("Counter is: " + stat); + + stat.reset(); + + assertEquals(0, stat.getCount()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/RangeStatisticTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/RangeStatisticTest.java new file mode 100644 index 0000000000..49caa986fc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/RangeStatisticTest.java @@ -0,0 +1,78 @@ +/** + * 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.management; + + +public class RangeStatisticTest extends StatisticTestSupport { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(RangeStatisticTest.class); + + /** + * Use case for RangeStatisticImpl class. + * @throws Exception + */ + public void testStatistic() throws Exception { + RangeStatisticImpl stat = new RangeStatisticImpl("myRange", "millis", "myDescription"); + assertStatistic(stat, "myRange", "millis", "myDescription"); + + assertRangeStatistic(stat); + } + + protected void assertRangeStatistic(RangeStatisticImpl stat) throws InterruptedException { + assertEquals(0, stat.getCurrent()); + assertEquals(0, stat.getLowWaterMark()); + assertEquals(0, stat.getHighWaterMark()); + + stat.setCurrent(100); + assertEquals(100, stat.getCurrent()); + assertEquals(100, stat.getLowWaterMark()); + assertEquals(100, stat.getHighWaterMark()); + + stat.setCurrent(50); + assertEquals(50, stat.getCurrent()); + assertEquals(50, stat.getLowWaterMark()); + assertEquals(100, stat.getHighWaterMark()); + + stat.setCurrent(200); + assertEquals(200, stat.getCurrent()); + assertEquals(50, stat.getLowWaterMark()); + assertEquals(200, stat.getHighWaterMark()); + + Thread.sleep(500); + + stat.setCurrent(10); + assertEquals(10, stat.getCurrent()); + assertEquals(10, stat.getLowWaterMark()); + assertEquals(200, stat.getHighWaterMark()); + + assertLastTimeNotStartTime(stat); + + LOG.info("Stat is: " + stat); + + stat.reset(); + + assertEquals(0, stat.getCurrent()); + assertEquals(0, stat.getLowWaterMark()); + assertEquals(0, stat.getHighWaterMark()); + + stat.setCurrent(100); + assertEquals(100, stat.getCurrent()); + assertEquals(100, stat.getLowWaterMark()); + assertEquals(100, stat.getHighWaterMark()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/StatisticTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/StatisticTestSupport.java new file mode 100644 index 0000000000..9d68cb24c2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/StatisticTestSupport.java @@ -0,0 +1,47 @@ +/** + * 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.management; + +import junit.framework.TestCase; + +public abstract class StatisticTestSupport extends TestCase { + + /** + * assert method used by the management related classes for its usecase. + * + * @param counter + * @param name + * @param unit + * @param description + */ + protected void assertStatistic(StatisticImpl counter, String name, String unit, String description) { + assertEquals(name, counter.getName()); + assertEquals(unit, counter.getUnit()); + assertEquals(description, counter.getDescription()); + } + + /** + * assert method to determine last time vs the start time. + * + * @param counter + */ + protected void assertLastTimeNotStartTime(StatisticImpl counter) { + assertTrue("Should not have start time the same as last sample time. Start time: " + + counter.getStartTime() + " lastTime: " + counter.getLastSampleTime(), counter + .getStartTime() != counter.getLastSampleTime()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/TimeStatisticTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/TimeStatisticTest.java new file mode 100644 index 0000000000..88ec2eac1c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/management/TimeStatisticTest.java @@ -0,0 +1,75 @@ +/** + * 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.management; + + +public class TimeStatisticTest extends StatisticTestSupport { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory + .getLog(TimeStatisticTest.class); + + /** + * Use case for TimeStatisticImpl class. + * @throws Exception + */ + public void testStatistic() throws Exception { + TimeStatisticImpl stat = new TimeStatisticImpl("myTimer", "millis", "myDescription"); + assertStatistic(stat, "myTimer", "millis", "myDescription"); + + assertEquals(0, stat.getCount()); + + stat.addTime(100); + assertEquals(1, stat.getCount()); + assertEquals(100, stat.getMinTime()); + assertEquals(100, stat.getMaxTime()); + + stat.addTime(403); + assertEquals(2, stat.getCount()); + assertEquals(100, stat.getMinTime()); + assertEquals(403, stat.getMaxTime()); + + stat.addTime(50); + assertEquals(3, stat.getCount()); + assertEquals(50, stat.getMinTime()); + assertEquals(403, stat.getMaxTime()); + + + assertEquals(553, stat.getTotalTime()); + + Thread.sleep(500); + + stat.addTime(10); + + assertLastTimeNotStartTime(stat); + + LOG.info("Stat is: " + stat); + + stat.reset(); + + assertEquals(0, stat.getCount()); + assertEquals(0, stat.getMinTime()); + assertEquals(0, stat.getMaxTime()); + assertEquals(0, stat.getTotalTime()); + + stat.addTime(100); + assertEquals(1, stat.getCount()); + assertEquals(100, stat.getMinTime()); + assertEquals(100, stat.getMaxTime()); + assertEquals(100, stat.getTotalTime()); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/MemoryPropertyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/MemoryPropertyTest.java new file mode 100644 index 0000000000..294916e0a1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/MemoryPropertyTest.java @@ -0,0 +1,75 @@ +/** + * 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.memory; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MemoryPropertyTest extends TestCase { + + private static final transient Logger LOG = LoggerFactory.getLogger(MemoryPropertyTest.class); + BrokerService broker; + + + /** + * Sets up a test where the producer and consumer have their own connection. + * + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + // Create broker from resource + LOG.info("Creating broker... "); + broker = createBroker("xbean:org/apache/activemq/memory/activemq.xml"); + LOG.info("Success"); + super.setUp(); + } + + protected BrokerService createBroker(String resource) throws Exception { + return BrokerFactory.createBroker(resource); + } + + /* + * Stops the Broker + * + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + LOG.info("Closing Broker"); + if (broker != null) { + broker.stop(); + } + LOG.info("Broker closed..."); + } + + public void testBrokerInitialized() { + assertTrue("We should have a broker", broker != null); + + assertEquals("test-broker", broker.getBrokerName()); + assertEquals(1024, broker.getSystemUsage().getMemoryUsage().getLimit()); + assertEquals(34, broker.getSystemUsage().getMemoryUsage().getPercentUsageMinDelta()); + + assertNotNull(broker.getSystemUsage().getStoreUsage().getStore()); + // non persistent broker so no temp storage + assertNull(broker.getSystemUsage().getTempUsage().getStore()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/activemq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/activemq.xml new file mode 100644 index 0000000000..511d6d1925 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/activemq.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/DummyMessage.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/DummyMessage.java new file mode 100644 index 0000000000..e5823d8943 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/DummyMessage.java @@ -0,0 +1,43 @@ +/** + * 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.memory.buffer; + +import org.apache.activemq.command.ActiveMQMessage; + +/** + * A message implementation which is useful for testing as we can spoof its size + * + * + */ +public class DummyMessage extends ActiveMQMessage { + + private int size; + + public DummyMessage(int size) { + this.size = size; + } + + public int getSize() { + return size; + } + + public String toString() { + return "DummyMessage[id=" + getMessageId() + " size=" + size + "]"; + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/MemoryBufferTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/MemoryBufferTestSupport.java new file mode 100644 index 0000000000..ea8f0a6c8d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/MemoryBufferTestSupport.java @@ -0,0 +1,67 @@ +/** + * 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.memory.buffer; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.memory.buffer.MessageBuffer; +import org.apache.activemq.memory.buffer.MessageQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public abstract class MemoryBufferTestSupport extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(MemoryBufferTestSupport.class); + + protected MessageBuffer buffer = createMessageBuffer(); + protected MessageQueue qA = buffer.createMessageQueue(); + protected MessageQueue qB = buffer.createMessageQueue(); + protected MessageQueue qC = buffer.createMessageQueue(); + protected int messageCount; + + protected abstract MessageBuffer createMessageBuffer(); + + protected void setUp() throws Exception { + buffer = createMessageBuffer(); + qA = buffer.createMessageQueue(); + qB = buffer.createMessageQueue(); + qC = buffer.createMessageQueue(); + } + + protected void dump() { + LOG.info("Dumping current state"); + dumpQueue(qA, "A"); + dumpQueue(qB, "B"); + dumpQueue(qC, "C"); + } + + protected void dumpQueue(MessageQueue queue, String name) { + LOG.info(" " + name + " = " + queue.getList()); + } + + protected ActiveMQMessage createMessage(int size) throws Exception { + DummyMessage answer = new DummyMessage(size); + answer.setIntProperty("counter", ++messageCount); + answer.setJMSMessageID("" + messageCount); + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/OrderBasedMemoryBufferTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/OrderBasedMemoryBufferTest.java new file mode 100644 index 0000000000..2e771f2706 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/OrderBasedMemoryBufferTest.java @@ -0,0 +1,74 @@ +/** + * 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.memory.buffer; + +import org.apache.activemq.memory.buffer.MessageBuffer; +import org.apache.activemq.memory.buffer.OrderBasedMessageBuffer; + + +/** + * + * + */ +public class OrderBasedMemoryBufferTest extends MemoryBufferTestSupport { + + public void testSizeWorks() throws Exception { + qA.add(createMessage(10)); + qB.add(createMessage(10)); + qB.add(createMessage(10)); + qC.add(createMessage(10)); + + dump(); + + assertEquals("buffer size", 40, buffer.getSize()); + assertEquals("qA", 10, qA.getSize()); + assertEquals("qB", 20, qB.getSize()); + assertEquals("qC", 10, qC.getSize()); + + qC.add(createMessage(10)); + + dump(); + + assertEquals("buffer size", 40, buffer.getSize()); + assertEquals("qA", 0, qA.getSize()); + assertEquals("qB", 20, qB.getSize()); + assertEquals("qC", 20, qC.getSize()); + + qB.add(createMessage(10)); + + dump(); + + assertEquals("buffer size", 40, buffer.getSize()); + assertEquals("qA", 0, qA.getSize()); + assertEquals("qB", 20, qB.getSize()); + assertEquals("qC", 20, qC.getSize()); + + qA.add(createMessage(10)); + + dump(); + + assertEquals("buffer size", 40, buffer.getSize()); + assertEquals("qA", 10, qA.getSize()); + assertEquals("qB", 10, qB.getSize()); + assertEquals("qC", 20, qC.getSize()); + } + + + protected MessageBuffer createMessageBuffer() { + return new OrderBasedMessageBuffer(40); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/SizeBasedMessageBufferTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/SizeBasedMessageBufferTest.java new file mode 100644 index 0000000000..ad02821c48 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/buffer/SizeBasedMessageBufferTest.java @@ -0,0 +1,57 @@ +/** + * 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.memory.buffer; + +import org.apache.activemq.memory.buffer.MessageBuffer; +import org.apache.activemq.memory.buffer.SizeBasedMessageBuffer; + + +/** + * + * + */ +public class SizeBasedMessageBufferTest extends MemoryBufferTestSupport { + + public void testSizeWorks() throws Exception { + qA.add(createMessage(10)); + qB.add(createMessage(10)); + qB.add(createMessage(10)); + qC.add(createMessage(10)); + + dump(); + + assertEquals("buffer size", 40, buffer.getSize()); + assertEquals("qA", 10, qA.getSize()); + assertEquals("qB", 20, qB.getSize()); + assertEquals("qC", 10, qC.getSize()); + + // now lets force an eviction + qC.add(createMessage(10)); + + dump(); + + assertEquals("buffer size", 40, buffer.getSize()); + assertEquals("qA", 10, qA.getSize()); + assertEquals("qB", 10, qB.getSize()); + assertEquals("qC", 20, qC.getSize()); + } + + + protected MessageBuffer createMessageBuffer() { + return new SizeBasedMessageBuffer(40); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/usage.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/usage.properties new file mode 100644 index 0000000000..b5d33d12a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/memory/usage.properties @@ -0,0 +1,19 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- +limit=1k +name=test-broker +delta=34 \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/BrokerNetworkWithStuckMessagesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/BrokerNetworkWithStuckMessagesTest.java new file mode 100644 index 0000000000..9f085b49c5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/BrokerNetworkWithStuckMessagesTest.java @@ -0,0 +1,629 @@ +/** + * 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.network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageNotWriteableException; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.management.ObjectName; + +import javax.management.openmbean.CompositeData; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTestSupport; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.DestinationInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatch; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.util.Wait; +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class duplicates most of the functionality in {@link NetworkTestSupport} + * and {@link BrokerTestSupport} because more control was needed over how brokers + * and connectors are created. Also, this test asserts message counts via JMX on + * each broker. + */ +public class BrokerNetworkWithStuckMessagesTest { + + private static final Logger LOG = LoggerFactory.getLogger(BrokerNetworkWithStuckMessagesTest.class); + + private BrokerService localBroker; + private BrokerService remoteBroker; + private BrokerService secondRemoteBroker; + private DemandForwardingBridge bridge; + + protected Map brokers = new HashMap(); + protected ArrayList connections = new ArrayList(); + + protected TransportConnector connector; + protected TransportConnector remoteConnector; + protected TransportConnector secondRemoteConnector; + + protected long idGenerator; + protected int msgIdGenerator; + protected int tempDestGenerator; + protected int maxWait = 4000; + protected String queueName = "TEST"; + + protected String amqDomain = "org.apache.activemq"; + + @Before + public void setUp() throws Exception { + + // For those who want visual confirmation: + // Uncomment the following to enable JMX support on a port number to use + // Jconsole to view each broker. You will need to add some calls to + // Thread.sleep() to be able to actually slow things down so that you + // can manually see JMX attrs. +// System.setProperty("com.sun.management.jmxremote", ""); +// System.setProperty("com.sun.management.jmxremote.port", "1099"); +// System.setProperty("com.sun.management.jmxremote.authenticate", "false"); +// System.setProperty("com.sun.management.jmxremote.ssl", "false"); + + // Create the local broker + createBroker(); + // Create the remote broker + createRemoteBroker(); + + // Remove the activemq-data directory from the creation of the remote broker + FileUtils.deleteDirectory(new File("activemq-data")); + + // Create a network bridge between the local and remote brokers so that + // demand-based forwarding can take place + NetworkBridgeConfiguration config = new NetworkBridgeConfiguration(); + config.setBrokerName("local"); + config.setDispatchAsync(false); + config.setDuplex(true); + + Transport localTransport = createTransport(); + Transport remoteTransport = createRemoteTransport(); + + // Create a network bridge between the two brokers + bridge = new DemandForwardingBridge(config, localTransport, remoteTransport); + bridge.setBrokerService(localBroker); + bridge.start(); + + + // introduce a second broker/bridge on remote that should not get any messages because of networkTtl=1 + // local <-> remote <-> secondRemote + createSecondRemoteBroker(); + config = new NetworkBridgeConfiguration(); + config.setBrokerName("remote"); + config.setDuplex(true); + + localTransport = createRemoteTransport(); + remoteTransport = createSecondRemoteTransport(); + + // Create a network bridge between the two brokers + bridge = new DemandForwardingBridge(config, localTransport, remoteTransport); + bridge.setBrokerService(remoteBroker); + bridge.start(); + + waitForBridgeFormation(); + } + + protected void waitForBridgeFormation() throws Exception { + for (final BrokerService broker : brokers.values()) { + if (!broker.getNetworkConnectors().isEmpty()) { + // Max wait here is 30 secs + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return !broker.getNetworkConnectors().get(0).activeBridges().isEmpty(); + }}); + } + } + } + + @After + public void tearDown() throws Exception { + bridge.stop(); + localBroker.stop(); + remoteBroker.stop(); + secondRemoteBroker.stop(); + } + + @Test(timeout=120000) + public void testBrokerNetworkWithStuckMessages() throws Exception { + + int sendNumMessages = 10; + int receiveNumMessages = 5; + + // Create a producer + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + // Create a destination on the local broker + ActiveMQDestination destinationInfo1 = null; + + // Send a 10 messages to the local broker + for (int i = 0; i < sendNumMessages; ++i) { + destinationInfo1 = createDestinationInfo(connection1, connectionInfo1, ActiveMQDestination.QUEUE_TYPE); + connection1.request(createMessage(producerInfo, destinationInfo1, DeliveryMode.NON_PERSISTENT)); + } + + // Ensure that there are 10 messages on the local broker + Object[] messages = browseQueueWithJmx(localBroker); + assertEquals(sendNumMessages, messages.length); + + // Create a synchronous consumer on the remote broker + StubConnection connection2 = createRemoteConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + ActiveMQDestination destinationInfo2 = + createDestinationInfo(connection2, connectionInfo2, ActiveMQDestination.QUEUE_TYPE); + final ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destinationInfo2); + connection2.send(consumerInfo2); + + // Consume 5 of the messages from the remote broker and ack them. + for (int i = 0; i < receiveNumMessages; ++i) { + Message message1 = receiveMessage(connection2, 20000); + assertNotNull(message1); + LOG.info("on remote, got: " + message1.getMessageId()); + connection2.send(createAck(consumerInfo2, message1, 1, MessageAck.INDIVIDUAL_ACK_TYPE)); + assertTrue("JMSActiveMQBrokerPath property present and correct", + ((ActiveMQMessage)message1).getStringProperty(ActiveMQMessage.BROKER_PATH_PROPERTY).contains(localBroker.getBroker().getBrokerId().toString())); + } + + // Ensure that there are zero messages on the local broker. This tells + // us that those messages have been prefetched to the remote broker + // where the demand exists. + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Object[] result = browseQueueWithJmx(localBroker); + return 0 == result.length; + } + }); + messages = browseQueueWithJmx(localBroker); + assertEquals(0, messages.length); + + // try and pull the messages from remote, should be denied b/c on networkTtl + LOG.info("creating demand on second remote..."); + StubConnection connection3 = createSecondRemoteConnection(); + ConnectionInfo connectionInfo3 = createConnectionInfo(); + SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); + connection3.send(connectionInfo3); + connection3.send(sessionInfo3); + ActiveMQDestination destinationInfo3 = + createDestinationInfo(connection3, connectionInfo3, ActiveMQDestination.QUEUE_TYPE); + final ConsumerInfo consumerInfoS3 = createConsumerInfo(sessionInfo3, destinationInfo3); + connection3.send(consumerInfoS3); + + Message messageExceedingTtl = receiveMessage(connection3, 5000); + if (messageExceedingTtl != null) { + LOG.error("got message on Second remote: " + messageExceedingTtl); + connection3.send(createAck(consumerInfoS3, messageExceedingTtl, 1, MessageAck.INDIVIDUAL_ACK_TYPE)); + } + + LOG.info("Closing consumer on remote"); + // Close the consumer on the remote broker + connection2.send(consumerInfo2.createRemoveCommand()); + // also close connection etc.. so messages get dropped from the local consumer q + connection2.send(connectionInfo2.createRemoveCommand()); + + // There should now be 5 messages stuck on the remote broker + assertTrue("correct stuck message count", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Object[] result = browseQueueWithJmx(remoteBroker); + return 5 == result.length; + } + })); + messages = browseQueueWithJmx(remoteBroker); + assertEquals(5, messages.length); + + assertTrue("can see broker path property", + ((String)((CompositeData)messages[1]).get("BrokerPath")).contains(localBroker.getBroker().getBrokerId().toString())); + + LOG.info("Messages now stuck on remote"); + + // receive again on the origin broker + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destinationInfo1); + connection1.send(consumerInfo1); + LOG.info("create local consumer: " + consumerInfo1); + + Message message1 = receiveMessage(connection1, 20000); + assertNotNull("Expect to get a replay as remote consumer is gone", message1); + connection1.send(createAck(consumerInfo1, message1, 1, MessageAck.INDIVIDUAL_ACK_TYPE)); + LOG.info("acked one message on origin, waiting for all messages to percolate back"); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Object[] result = browseQueueWithJmx(localBroker); + return 4 == result.length; + } + }); + messages = browseQueueWithJmx(localBroker); + assertEquals(4, messages.length); + + LOG.info("checking for messages on remote again"); + // messages won't migrate back again till consumer closes + connection2 = createRemoteConnection(); + connectionInfo2 = createConnectionInfo(); + sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + ConsumerInfo consumerInfo3 = createConsumerInfo(sessionInfo2, destinationInfo2); + connection2.send(consumerInfo3); + message1 = receiveMessage(connection2, 20000); + assertNull("Messages have migrated back: " + message1, message1); + + // Consume the last 4 messages from the local broker and ack them just + // to clean up the queue. + int counter = 1; + for (; counter < receiveNumMessages; counter++) { + message1 = receiveMessage(connection1); + LOG.info("local consume of: " + (message1 != null ? message1.getMessageId() : " null")); + connection1.send(createAck(consumerInfo1, message1, 1, MessageAck.INDIVIDUAL_ACK_TYPE)); + } + // Ensure that 5 messages were received + assertEquals(receiveNumMessages, counter); + + // verify all messages consumed + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Object[] result = browseQueueWithJmx(remoteBroker); + return 0 == result.length; + } + }); + messages = browseQueueWithJmx(remoteBroker); + assertEquals(0, messages.length); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Object[] result = browseQueueWithJmx(localBroker); + return 0 == result.length; + } + }); + messages = browseQueueWithJmx(localBroker); + assertEquals(0, messages.length); + + // Close the consumer on the remote broker + connection2.send(consumerInfo3.createRemoveCommand()); + + connection1.stop(); + connection2.stop(); + connection3.stop(); + } + + protected BrokerService createBroker() throws Exception { + localBroker = new BrokerService(); + localBroker.setBrokerName("localhost"); + localBroker.setUseJmx(true); + localBroker.setPersistenceAdapter(null); + localBroker.setPersistent(false); + connector = createConnector(); + localBroker.addConnector(connector); + configureBroker(localBroker); + localBroker.start(); + localBroker.waitUntilStarted(); + + localBroker.getManagementContext().setConnectorPort(2221); + + brokers.put(localBroker.getBrokerName(), localBroker); + + return localBroker; + } + + private void configureBroker(BrokerService broker) { + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setExpireMessagesPeriod(0); + ConditionalNetworkBridgeFilterFactory filterFactory = new ConditionalNetworkBridgeFilterFactory(); + filterFactory.setReplayWhenNoConsumers(true); + defaultEntry.setNetworkBridgeFilterFactory(filterFactory); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + } + + protected BrokerService createRemoteBroker() throws Exception { + remoteBroker = new BrokerService(); + remoteBroker.setBrokerName("remotehost"); + remoteBroker.setUseJmx(true); + remoteBroker.setPersistenceAdapter(null); + remoteBroker.setPersistent(false); + remoteConnector = createRemoteConnector(); + remoteBroker.addConnector(remoteConnector); + configureBroker(remoteBroker); + remoteBroker.start(); + remoteBroker.waitUntilStarted(); + + remoteBroker.getManagementContext().setConnectorPort(2222); + + brokers.put(remoteBroker.getBrokerName(), remoteBroker); + + return remoteBroker; + } + + protected BrokerService createSecondRemoteBroker() throws Exception { + secondRemoteBroker = new BrokerService(); + secondRemoteBroker.setBrokerName("secondRemotehost"); + secondRemoteBroker.setUseJmx(false); + secondRemoteBroker.setPersistenceAdapter(null); + secondRemoteBroker.setPersistent(false); + secondRemoteConnector = createSecondRemoteConnector(); + secondRemoteBroker.addConnector(secondRemoteConnector); + configureBroker(secondRemoteBroker); + secondRemoteBroker.start(); + secondRemoteBroker.waitUntilStarted(); + + brokers.put(secondRemoteBroker.getBrokerName(), secondRemoteBroker); + + return secondRemoteBroker; + } + + protected Transport createTransport() throws Exception { + Transport transport = TransportFactory.connect(connector.getServer().getConnectURI()); + return transport; + } + + protected Transport createRemoteTransport() throws Exception { + Transport transport = TransportFactory.connect(remoteConnector.getServer().getConnectURI()); + return transport; + } + + protected Transport createSecondRemoteTransport() throws Exception { + Transport transport = TransportFactory.connect(secondRemoteConnector.getServer().getConnectURI()); + return transport; + } + + protected TransportConnector createConnector() throws Exception, IOException, URISyntaxException { + return new TransportConnector(TransportFactory.bind(new URI(getLocalURI()))); + } + + protected TransportConnector createRemoteConnector() throws Exception, IOException, URISyntaxException { + return new TransportConnector(TransportFactory.bind(new URI(getRemoteURI()))); + } + + protected TransportConnector createSecondRemoteConnector() throws Exception, IOException, URISyntaxException { + return new TransportConnector(TransportFactory.bind(new URI(getSecondRemoteURI()))); + } + + protected String getRemoteURI() { + return "vm://remotehost"; + } + + protected String getSecondRemoteURI() { + return "vm://secondRemotehost"; + } + + protected String getLocalURI() { + return "vm://localhost"; + } + + protected StubConnection createConnection() throws Exception { + Transport transport = TransportFactory.connect(connector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + protected StubConnection createRemoteConnection() throws Exception { + Transport transport = TransportFactory.connect(remoteConnector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + protected StubConnection createSecondRemoteConnection() throws Exception { + Transport transport = TransportFactory.connect(secondRemoteConnector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + @SuppressWarnings({ "unchecked", "unused" }) + private Object[] browseQueueWithJms(BrokerService broker) throws Exception { + Object[] messages = null; + Connection connection = null; + Session session = null; + + try { + URI brokerUri = connector.getUri(); + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUri.toString()); + connection = connectionFactory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(queueName); + QueueBrowser browser = session.createBrowser(destination); + List list = new ArrayList(); + for (Enumeration enumn = browser.getEnumeration(); enumn.hasMoreElements();) { + list.add(enumn.nextElement()); + } + messages = list.toArray(); + } + finally { + if (session != null) { + session.close(); + } + if (connection != null) { + connection.close(); + } + } + LOG.info("+Browsed with JMS: " + messages.length); + + return messages; + } + + private Object[] browseQueueWithJmx(BrokerService broker) throws Exception { + Hashtable params = new Hashtable(); + params.put("brokerName", broker.getBrokerName()); + params.put("type", "Broker"); + params.put("destinationType", "Queue"); + params.put("destinationName", queueName); + ObjectName queueObjectName = ObjectName.getInstance(amqDomain, params); + + ManagementContext mgmtCtx = broker.getManagementContext(); + QueueViewMBean queueView = (QueueViewMBean)mgmtCtx.newProxyInstance(queueObjectName, QueueViewMBean.class, true); + + Object[] messages = queueView.browse(); + + LOG.info("+Browsed with JMX: " + messages.length); + + return messages; + } + + protected ConnectionInfo createConnectionInfo() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + info.setConnectionId(new ConnectionId("connection:" + (++idGenerator))); + info.setClientId(info.getConnectionId().getValue()); + return info; + } + + protected SessionInfo createSessionInfo(ConnectionInfo connectionInfo) throws Exception { + SessionInfo info = new SessionInfo(connectionInfo, ++idGenerator); + return info; + } + + protected ProducerInfo createProducerInfo(SessionInfo sessionInfo) throws Exception { + ProducerInfo info = new ProducerInfo(sessionInfo, ++idGenerator); + return info; + } + + protected ConsumerInfo createConsumerInfo(SessionInfo sessionInfo, ActiveMQDestination destination) throws Exception { + ConsumerInfo info = new ConsumerInfo(sessionInfo, ++idGenerator); + info.setBrowser(false); + info.setDestination(destination); + info.setPrefetchSize(1000); + info.setDispatchAsync(false); + return info; + } + + protected DestinationInfo createTempDestinationInfo(ConnectionInfo connectionInfo, byte destinationType) { + DestinationInfo info = new DestinationInfo(); + info.setConnectionId(connectionInfo.getConnectionId()); + info.setOperationType(DestinationInfo.ADD_OPERATION_TYPE); + info.setDestination(ActiveMQDestination.createDestination(info.getConnectionId() + ":" + (++tempDestGenerator), destinationType)); + return info; + } + + protected ActiveMQDestination createDestinationInfo(StubConnection connection, ConnectionInfo connectionInfo1, byte destinationType) throws Exception { + if ((destinationType & ActiveMQDestination.TEMP_MASK) != 0) { + DestinationInfo info = createTempDestinationInfo(connectionInfo1, destinationType); + connection.send(info); + return info.getDestination(); + } else { + return ActiveMQDestination.createDestination(queueName, destinationType); + } + } + + protected Message createMessage(ProducerInfo producerInfo, ActiveMQDestination destination, int deliveryMode) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(deliveryMode == DeliveryMode.PERSISTENT); + return message; + } + + protected Message createMessage(ProducerInfo producerInfo, ActiveMQDestination destination) { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setMessageId(new MessageId(producerInfo, ++msgIdGenerator)); + message.setDestination(destination); + message.setPersistent(false); + try { + message.setText("Test Message Payload."); + } catch (MessageNotWriteableException e) { + } + return message; + } + + protected MessageAck createAck(ConsumerInfo consumerInfo, Message msg, int count, byte ackType) { + MessageAck ack = new MessageAck(); + ack.setAckType(ackType); + ack.setConsumerId(consumerInfo.getConsumerId()); + ack.setDestination(msg.getDestination()); + ack.setLastMessageId(msg.getMessageId()); + ack.setMessageCount(count); + return ack; + } + + public Message receiveMessage(StubConnection connection) throws InterruptedException { + return receiveMessage(connection, maxWait); + } + + public Message receiveMessage(StubConnection connection, long timeout) throws InterruptedException { + while (true) { + Object o = connection.getDispatchQueue().poll(timeout, TimeUnit.MILLISECONDS); + + if (o == null) { + return null; + } + if (o instanceof MessageDispatch) { + + MessageDispatch dispatch = (MessageDispatch)o; + if (dispatch.getMessage() == null) { + return null; + } + dispatch.setMessage(dispatch.getMessage().copy()); + dispatch.getMessage().setRedeliveryCounter(dispatch.getRedeliveryCounter()); + return dispatch.getMessage(); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/CheckDuplicateMessagesOnDuplexTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/CheckDuplicateMessagesOnDuplexTest.java new file mode 100644 index 0000000000..68681c6ed2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/CheckDuplicateMessagesOnDuplexTest.java @@ -0,0 +1,356 @@ +/** + * 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.network; + +import java.io.File; +import java.io.IOException; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.net.ServerSocketFactory; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.command.Response; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.leveldb.LevelDBPersistenceAdapter; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFilter; +import org.apache.activemq.transport.TransportServer; +import org.apache.activemq.transport.nio.NIOTransport; +import org.apache.activemq.transport.nio.NIOTransportFactory; +import org.apache.activemq.transport.tcp.TcpTransportFactory; +import org.apache.activemq.transport.tcp.TcpTransportServer; +import org.apache.activemq.wireformat.WireFormat; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static org.junit.Assert.*; + +/** + * + * @author x22koe + */ +public class CheckDuplicateMessagesOnDuplexTest { + + private static final Logger log = LoggerFactory.getLogger(CheckDuplicateMessagesOnDuplexTest.class); + private BrokerService localBroker; + private BrokerService remoteBroker; + private ActiveMQConnectionFactory localFactory; + private ActiveMQConnectionFactory remoteFactory; + private Session localSession; + private MessageConsumer consumer; + private Session remoteSession; + private MessageProducer producer; + private Connection remoteConnection; + private Connection localConnection; + private DebugTransportFilter debugTransportFilter; + private boolean useLevelDB = false; + + public CheckDuplicateMessagesOnDuplexTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void testConnectionLossBehaviorBeforeAckIsSent() throws Exception { + createBrokers(); + localBroker.deleteAllMessages(); + remoteBroker.deleteAllMessages(); + startBrokers(); + openConnections(); + + Thread.sleep(1000); + log.info("\n\n==============================================\nsend hello1\n"); + + // simulate network failure between REMOTE and LOCAL just before the reception response is sent back to REMOTE + debugTransportFilter.closeOnResponse = true; + + producer.send(remoteSession.createTextMessage("hello1")); + Message msg = consumer.receive(30000); + + assertNotNull("expected hello1", msg); + assertEquals("hello1", ((TextMessage) msg).getText()); + + Thread.sleep(1000); + log.info("\n\n------------------------------------------\nsend hello2\n"); + + producer.send(remoteSession.createTextMessage("hello2")); + msg = consumer.receive(30000); + + assertNotNull("expected hello2", msg); + assertEquals("hello2", ((TextMessage) msg).getText()); + + closeLocalConnection(); + + Thread.sleep(1000); + log.info("\n\n------------------------------------------\nsend hello3\n"); + + openLocalConnection(); + + Thread.sleep(1000); + + producer.send(remoteSession.createTextMessage("hello3")); + msg = consumer.receive(30000); + + assertNotNull("expected hello3", msg); + assertEquals("hello3", ((TextMessage) msg).getText()); + + Thread.sleep(1000); + log.info("\n\n==============================================\n\n"); + + closeConnections(); + stopBrokers(); + + // restart the local broker, which should be empty + + Thread.sleep(1000); + log.info("\n\n##############################################\n\n"); + + createLocalBroker(); + startLocalBroker(); + openLocalConnection(); + + // this should not return the "hello1" message + msg = consumer.receive(1000); + + closeLocalConnection(); + stopLocalBroker(); + + assertNull(msg); + } + + private void createBrokers() throws Exception { + createLocalBroker(); + createRemoteBroker(); + } + + private void createLocalBroker() throws Exception { + localBroker = new BrokerService(); + localBroker.setBrokerName("LOCAL"); + localBroker.setUseJmx(true); + localBroker.setSchedulePeriodForDestinationPurge(5000); + ManagementContext managementContext = new ManagementContext(); + managementContext.setCreateConnector(false); + localBroker.setManagementContext(managementContext); + PersistenceAdapter persistenceAdapter = persistanceAdapterFactory("target/local"); + localBroker.setPersistenceAdapter(persistenceAdapter); + List transportConnectors = new ArrayList(); + DebugTransportFactory tf = new DebugTransportFactory(); + TransportServer transport = tf.doBind(URI.create("nio://127.0.0.1:23539")); + TransportConnector transportConnector = new TransportConnector(transport); + transportConnector.setName("tc"); + transportConnector.setAuditNetworkProducers(true); + transportConnectors.add(transportConnector); + localBroker.setTransportConnectors(transportConnectors); + } + + private void createRemoteBroker() throws Exception { + remoteBroker = new BrokerService(); + remoteBroker.setBrokerName("REMOTE"); + remoteBroker.setUseJmx(true); + remoteBroker.setSchedulePeriodForDestinationPurge(5000); + ManagementContext managementContext = new ManagementContext(); + managementContext.setCreateConnector(false); + remoteBroker.setManagementContext(managementContext); + PersistenceAdapter persistenceAdapter = persistanceAdapterFactory("target/remote"); + remoteBroker.setPersistenceAdapter(persistenceAdapter); + List networkConnectors = new ArrayList(); + DiscoveryNetworkConnector networkConnector = new DiscoveryNetworkConnector(); + networkConnector.setName("to local"); + // set maxInactivityDuration to 0, otherwise the broker restarts while you are in the debugger + networkConnector.setUri(URI.create("static://(tcp://127.0.0.1:23539?wireFormat.maxInactivityDuration=0)")); + networkConnector.setDuplex(true); + //networkConnector.setNetworkTTL(5); + //networkConnector.setDynamicOnly(true); + networkConnector.setAlwaysSyncSend(true); + networkConnector.setDecreaseNetworkConsumerPriority(false); + networkConnector.setPrefetchSize(1); + networkConnector.setCheckDuplicateMessagesOnDuplex(true); + networkConnectors.add(networkConnector); + remoteBroker.setNetworkConnectors(networkConnectors); + } + + private void startBrokers() throws Exception { + startLocalBroker(); + startRemoteBroker(); + } + + private void startLocalBroker() throws Exception { + localBroker.start(); + localBroker.waitUntilStarted(); + } + + private void startRemoteBroker() throws Exception { + remoteBroker.start(); + remoteBroker.waitUntilStarted(); + } + + private void openConnections() throws JMSException { + openLocalConnection(); + openRemoteConnection(); + } + + private void openLocalConnection() throws JMSException { + localFactory = new ActiveMQConnectionFactory(localBroker.getVmConnectorURI()); + //localFactory.setSendAcksAsync(false); + localConnection = localFactory.createConnection(); + localConnection.start(); + localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = localSession.createConsumer(localSession.createQueue("testqueue")); + } + + private void openRemoteConnection() throws JMSException { + remoteFactory = new ActiveMQConnectionFactory(remoteBroker.getVmConnectorURI()); + //remoteFactory.setSendAcksAsync(false); + remoteConnection = remoteFactory.createConnection(); + remoteConnection.start(); + remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = remoteSession.createProducer(remoteSession.createQueue("testqueue")); + } + + private void closeConnections() throws JMSException { + closeLocalConnection(); + closeRemoteConnection(); + } + + private void closeLocalConnection() throws JMSException { + localConnection.close(); + } + + private void closeRemoteConnection() throws JMSException { + remoteConnection.close(); + } + + private void stopBrokers() throws Exception { + stopRemoteBroker(); + stopLocalBroker(); + } + + private void stopLocalBroker() throws Exception { + localBroker.stop(); + localBroker.waitUntilStopped(); + } + + private void stopRemoteBroker() throws Exception { + remoteBroker.stop(); + remoteBroker.waitUntilStopped(); + } + + private PersistenceAdapter persistanceAdapterFactory(String path) { + if (useLevelDB) { + return persistanceAdapterFactory_LevelDB(path); + } else { + return persistanceAdapterFactory_KahaDB(path); + } + } + + private PersistenceAdapter persistanceAdapterFactory_KahaDB(String path) { + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = new KahaDBPersistenceAdapter(); + kahaDBPersistenceAdapter.setDirectory(new File(path)); + kahaDBPersistenceAdapter.setIgnoreMissingJournalfiles(true); + kahaDBPersistenceAdapter.setCheckForCorruptJournalFiles(true); + kahaDBPersistenceAdapter.setChecksumJournalFiles(true); + return kahaDBPersistenceAdapter; + } + + private PersistenceAdapter persistanceAdapterFactory_LevelDB(String path) { + LevelDBPersistenceAdapter levelDBPersistenceAdapter = new LevelDBPersistenceAdapter(); + levelDBPersistenceAdapter.setDirectory(new File(path)); + return levelDBPersistenceAdapter; + } + + private class DebugTransportFactory extends NIOTransportFactory { + + @Override + protected TcpTransportServer createTcpTransportServer(URI location, ServerSocketFactory serverSocketFactory) + throws IOException, URISyntaxException { + return new DebugTransportServer(this, location, serverSocketFactory); + } + } + + private class DebugTransportServer extends TcpTransportServer { + + public DebugTransportServer(TcpTransportFactory transportFactory, URI location, + ServerSocketFactory serverSocketFactory) throws IOException, URISyntaxException { + super(transportFactory, location, serverSocketFactory); + } + + @Override + protected Transport createTransport(Socket socket, WireFormat format) throws IOException { + Transport transport; + transport = new NIOTransport(format, socket); + debugTransportFilter = new DebugTransportFilter(transport); + return debugTransportFilter; + } + } + + private class DebugTransportFilter extends TransportFilter { + + boolean closeOnResponse = false; + + public DebugTransportFilter(Transport next) { + super(next); + } + + @Override + public void oneway(Object command) throws IOException { + if (closeOnResponse && command instanceof Response) { + closeOnResponse = false; + log.warn("\n\nclosing connection before response is sent\n\n"); + try { + ((NIOTransport) next).stop(); + } catch (Exception ex) { + log.error("couldn't stop niotransport", ex); + } + // don't send response + return; + } + super.oneway(command); + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/CompressionOverNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/CompressionOverNetworkTest.java new file mode 100644 index 0000000000..58af6dc224 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/CompressionOverNetworkTest.java @@ -0,0 +1,330 @@ +/** + * 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.network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.util.Arrays; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.StreamMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQBytesMessage; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMapMessage; +import org.apache.activemq.command.ActiveMQObjectMessage; +import org.apache.activemq.command.ActiveMQStreamMessage; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.util.Wait; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +public class CompressionOverNetworkTest { + + protected static final int RECEIVE_TIMEOUT_MILLS = 10000; + protected static final int MESSAGE_COUNT = 10; + private static final Logger LOG = LoggerFactory.getLogger(CompressionOverNetworkTest.class); + + protected AbstractApplicationContext context; + protected Connection localConnection; + protected Connection remoteConnection; + protected BrokerService localBroker; + protected BrokerService remoteBroker; + protected Session localSession; + protected Session remoteSession; + protected ActiveMQDestination included; + + @Test + public void testCompressedOverCompressedNetwork() throws Exception { + + ActiveMQConnection localAmqConnection = (ActiveMQConnection) localConnection; + localAmqConnection.setUseCompression(true); + + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 1, included); + + StringBuilder payload = new StringBuilder("test-"); + for (int i = 0; i < 100; ++i) { + payload.append(UUID.randomUUID().toString()); + } + + Message test = localSession.createTextMessage(payload.toString()); + producer.send(test); + Message msg = consumer1.receive(RECEIVE_TIMEOUT_MILLS); + assertNotNull(msg); + ActiveMQTextMessage message = (ActiveMQTextMessage) msg; + assertTrue(message.isCompressed()); + assertEquals(payload.toString(), message.getText()); + } + + @Test + public void testTextMessageCompression() throws Exception { + + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 1, included); + + StringBuilder payload = new StringBuilder("test-"); + for (int i = 0; i < 100; ++i) { + payload.append(UUID.randomUUID().toString()); + } + + Message test = localSession.createTextMessage(payload.toString()); + producer.send(test); + Message msg = consumer1.receive(RECEIVE_TIMEOUT_MILLS); + assertNotNull(msg); + ActiveMQTextMessage message = (ActiveMQTextMessage) msg; + assertTrue(message.isCompressed()); + assertEquals(payload.toString(), message.getText()); + } + + @Test + public void testBytesMessageCompression() throws Exception { + + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 1, included); + + StringBuilder payload = new StringBuilder("test-"); + for (int i = 0; i < 100; ++i) { + payload.append(UUID.randomUUID().toString()); + } + + byte[] bytes = payload.toString().getBytes("UTF-8"); + + BytesMessage test = localSession.createBytesMessage(); + test.writeBytes(bytes); + producer.send(test); + Message msg = consumer1.receive(RECEIVE_TIMEOUT_MILLS); + assertNotNull(msg); + ActiveMQBytesMessage message = (ActiveMQBytesMessage) msg; + assertTrue(message.isCompressed()); + assertTrue(message.getContent().getLength() < bytes.length); + + byte[] result = new byte[bytes.length]; + assertEquals(bytes.length, message.readBytes(result)); + assertEquals(-1, message.readBytes(result)); + + for(int i = 0; i < bytes.length; ++i) { + assertEquals(bytes[i], result[i]); + } + } + + @Test + public void testStreamMessageCompression() throws Exception { + + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 1, included); + + StreamMessage test = localSession.createStreamMessage(); + + for (int i = 0; i < 100; ++i) { + test.writeString("test string: " + i); + } + + producer.send(test); + Message msg = consumer1.receive(RECEIVE_TIMEOUT_MILLS); + assertNotNull(msg); + ActiveMQStreamMessage message = (ActiveMQStreamMessage) msg; + assertTrue(message.isCompressed()); + + for (int i = 0; i < 100; ++i) { + assertEquals("test string: " + i, message.readString()); + } + } + + @Test + public void testMapMessageCompression() throws Exception { + + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 1, included); + + MapMessage test = localSession.createMapMessage(); + + for (int i = 0; i < 100; ++i) { + test.setString(Integer.toString(i), "test string: " + i); + } + + producer.send(test); + Message msg = consumer1.receive(RECEIVE_TIMEOUT_MILLS); + assertNotNull(msg); + ActiveMQMapMessage message = (ActiveMQMapMessage) msg; + assertTrue(message.isCompressed()); + + for (int i = 0; i < 100; ++i) { + assertEquals("test string: " + i, message.getString(Integer.toString(i))); + } + } + + @Test + public void testObjectMessageCompression() throws Exception { + + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 1, included); + + StringBuilder payload = new StringBuilder("test-"); + for (int i = 0; i < 100; ++i) { + payload.append(UUID.randomUUID().toString()); + } + + Message test = localSession.createObjectMessage(payload.toString()); + producer.send(test); + Message msg = consumer1.receive(RECEIVE_TIMEOUT_MILLS); + assertNotNull(msg); + ActiveMQObjectMessage message = (ActiveMQObjectMessage) msg; + assertTrue(message.isCompressed()); + assertEquals(payload.toString(), message.getObject()); + } + + private void waitForConsumerRegistration(final BrokerService brokerService, final int min, final ActiveMQDestination destination) throws Exception { + assertTrue("Internal bridge consumers registered in time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Object[] bridges = brokerService.getNetworkConnectors().get(0).bridges.values().toArray(); + if (bridges.length > 0) { + LOG.info(brokerService + " bridges " + Arrays.toString(bridges)); + DemandForwardingBridgeSupport demandForwardingBridgeSupport = (DemandForwardingBridgeSupport) bridges[0]; + ConcurrentHashMap forwardingBridges = demandForwardingBridgeSupport.getLocalSubscriptionMap(); + LOG.info(brokerService + " bridge " + demandForwardingBridgeSupport + ", localSubs: " + forwardingBridges); + if (!forwardingBridges.isEmpty()) { + for (DemandSubscription demandSubscription : forwardingBridges.values()) { + if (demandSubscription.getLocalInfo().getDestination().equals(destination)) { + LOG.info(brokerService + " DemandSubscription " + demandSubscription + ", size: " + demandSubscription.size()); + return demandSubscription.size() >= min; + } + } + } + } + return false; + } + })); + } + + @Before + public void setUp() throws Exception { + doSetUp(true); + } + + @After + public void tearDown() throws Exception { + doTearDown(); + } + + protected void doTearDown() throws Exception { + localConnection.close(); + remoteConnection.close(); + localBroker.stop(); + remoteBroker.stop(); + } + + protected void doSetUp(boolean deleteAllMessages) throws Exception { + localBroker = createLocalBroker(); + localBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); + localBroker.start(); + localBroker.waitUntilStarted(); + remoteBroker = createRemoteBroker(); + remoteBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); + remoteBroker.start(); + remoteBroker.waitUntilStarted(); + URI localURI = localBroker.getVmConnectorURI(); + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(localURI); + fac.setAlwaysSyncSend(true); + fac.setDispatchAsync(false); + localConnection = fac.createConnection(); + localConnection.setClientID("clientId"); + localConnection.start(); + URI remoteURI = remoteBroker.getVmConnectorURI(); + fac = new ActiveMQConnectionFactory(remoteURI); + remoteConnection = fac.createConnection(); + remoteConnection.setClientID("clientId"); + remoteConnection.start(); + included = new ActiveMQTopic("include.test.bar"); + localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + protected String getRemoteBrokerURI() { + return "org/apache/activemq/network/remoteBroker.xml"; + } + + protected String getLocalBrokerURI() { + return "org/apache/activemq/network/localBroker.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); + factory.afterPropertiesSet(); + BrokerService result = factory.getBroker(); + + for (NetworkConnector connector : result.getNetworkConnectors()) { + connector.setUseCompression(true); + } + + return result; + } + + protected BrokerService createLocalBroker() throws Exception { + return createBroker(getLocalBrokerURI()); + } + + protected BrokerService createRemoteBroker() throws Exception { + return createBroker(getRemoteBrokerURI()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DemandForwardingBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DemandForwardingBridgeFilterTest.java new file mode 100644 index 0000000000..087ddd0a45 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DemandForwardingBridgeFilterTest.java @@ -0,0 +1,211 @@ +/** + * 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.network; + +import junit.framework.Test; + +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; + +import java.util.Arrays; + + +public class DemandForwardingBridgeFilterTest extends NetworkTestSupport { + + private DemandForwardingBridge bridge; + + private StubConnection producerConnection; + + private ProducerInfo producerInfo; + + private StubConnection consumerConnection; + + private SessionInfo consumerSessionInfo; + + public void testWildcardOnExcludedDestination() throws Exception { + + NetworkBridgeConfiguration configuration = getDefaultBridgeConfiguration(); + + configuration.setExcludedDestinations(Arrays.asList(ActiveMQDestination.createDestination("OTHER.>", + ActiveMQDestination.TOPIC_TYPE))); + configuration.setDynamicallyIncludedDestinations(Arrays.asList(ActiveMQDestination.createDestination( + "TEST", ActiveMQDestination.QUEUE_TYPE))); + + configureAndStartBridge(configuration); + + assertReceiveMessageOn("TEST", ActiveMQDestination.QUEUE_TYPE); + assertReceiveNoMessageOn("OTHER.T1", ActiveMQDestination.TOPIC_TYPE); + } + + public void testWildcardOnTwoExcludedDestination() throws Exception { + NetworkBridgeConfiguration configuration = getDefaultBridgeConfiguration(); + + configuration.setExcludedDestinations(Arrays.asList(ActiveMQDestination.createDestination("OTHER.>", ActiveMQDestination.QUEUE_TYPE), + ActiveMQDestination.createDestination("TEST.X1", ActiveMQDestination.QUEUE_TYPE))); + configuration.setDynamicallyIncludedDestinations(Arrays.asList(ActiveMQDestination.createDestination( + "TEST.X2", ActiveMQDestination.QUEUE_TYPE))); + + configureAndStartBridge(configuration); + + assertReceiveMessageOn("TEST.X2", ActiveMQDestination.QUEUE_TYPE); + assertReceiveNoMessageOn("OTHER.X1", ActiveMQDestination.QUEUE_TYPE); + assertReceiveNoMessageOn("TEST.X1", ActiveMQDestination.QUEUE_TYPE); + } + + + public void testWildcardOnDynamicallyIncludedDestination() throws Exception { + + NetworkBridgeConfiguration configuration = getDefaultBridgeConfiguration(); + + configuration.setDynamicallyIncludedDestinations(Arrays.asList(ActiveMQDestination.createDestination("OTHER.>", ActiveMQDestination.QUEUE_TYPE), + ActiveMQDestination.createDestination("TEST.X2", ActiveMQDestination.QUEUE_TYPE))); + + configureAndStartBridge(configuration); + + + assertReceiveMessageOn("OTHER.X1", ActiveMQDestination.QUEUE_TYPE); + assertReceiveMessageOn("TEST.X2", ActiveMQDestination.QUEUE_TYPE); + } + + public void testDistinctTopicAndQueue() throws Exception { + + NetworkBridgeConfiguration configuration = getDefaultBridgeConfiguration(); + + configuration.setExcludedDestinations(Arrays.asList(ActiveMQDestination.createDestination(">", + ActiveMQDestination.TOPIC_TYPE))); + configuration.setDynamicallyIncludedDestinations(Arrays.asList(ActiveMQDestination.createDestination( + ">", ActiveMQDestination.QUEUE_TYPE))); + + configureAndStartBridge(configuration); + + assertReceiveMessageOn("TEST", ActiveMQDestination.QUEUE_TYPE); + assertReceiveNoMessageOn("TEST", ActiveMQDestination.TOPIC_TYPE); + } + + public void testListOfExcludedDestinationWithWildcard() throws Exception { + + NetworkBridgeConfiguration configuration = getDefaultBridgeConfiguration(); + + configuration.setExcludedDestinations(Arrays.asList(ActiveMQDestination.createDestination("OTHER.>", ActiveMQDestination.TOPIC_TYPE), + ActiveMQDestination.createDestination("TEST.*", ActiveMQDestination.TOPIC_TYPE))); + configuration.setDynamicallyIncludedDestinations(Arrays.asList(ActiveMQDestination.createDestination( + "TEST.X1", ActiveMQDestination.QUEUE_TYPE))); + + configureAndStartBridge(configuration); + + assertReceiveMessageOn("TEST.X1", ActiveMQDestination.QUEUE_TYPE); + assertReceiveNoMessageOn("OTHER.T1", ActiveMQDestination.TOPIC_TYPE); + assertReceiveNoMessageOn("OTHER.T2", ActiveMQDestination.TOPIC_TYPE); + } + + private void assertReceiveMessageOn(String destinationName, byte destinationType) throws Exception, + InterruptedException { + + ActiveMQDestination destination = ActiveMQDestination.createDestination(destinationName, destinationType); + + // Send the message to the local broker. + producerConnection.send(createMessage(producerInfo, destination, destinationType)); + + // Make sure the message was delivered via the remote. + Message m = createConsumerAndReceiveMessage(destination); + + assertNotNull(m); + } + + private void assertReceiveNoMessageOn(String destinationName, byte destinationType) throws Exception, + InterruptedException { + + ActiveMQDestination destination = ActiveMQDestination.createDestination(destinationName, destinationType); + + // Send the message to the local broker. + producerConnection.send(createMessage(producerInfo, destination, destinationType)); + + // Make sure the message was delivered via the remote. + Message m = createConsumerAndReceiveMessage(destination); + assertNull(m); + } + + private Message createConsumerAndReceiveMessage(ActiveMQDestination destination) throws Exception { + // Now create remote consumer that should cause message to move to this + // remote consumer. + ConsumerInfo consumerInfo = createConsumerInfo(consumerSessionInfo, destination); + consumerConnection.send(consumerInfo); + + Message m = receiveMessage(consumerConnection); + return m; + } + + protected void setUp() throws Exception { + super.setUp(); + + + producerConnection = createConnection(); + ConnectionInfo producerConnectionInfo = createConnectionInfo(); + SessionInfo producerSessionInfo = createSessionInfo(producerConnectionInfo); + producerInfo = createProducerInfo(producerSessionInfo); + producerConnection.send(producerConnectionInfo); + producerConnection.send(producerSessionInfo); + producerConnection.send(producerInfo); + + consumerConnection = createRemoteConnection(); + ConnectionInfo consumerConnectionInfo = createConnectionInfo(); + consumerSessionInfo = createSessionInfo(consumerConnectionInfo); + consumerConnection.send(consumerConnectionInfo); + consumerConnection.send(consumerSessionInfo); + } + + protected void tearDown() throws Exception { + bridge.stop(); + super.tearDown(); + } + + public static Test suite() { + return suite(DemandForwardingBridgeFilterTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public NetworkBridgeConfiguration getDefaultBridgeConfiguration() { + NetworkBridgeConfiguration config = new NetworkBridgeConfiguration(); + config.setBrokerName("local"); + config.setDispatchAsync(false); + return config; + } + + private void configureAndStartBridge(NetworkBridgeConfiguration configuration) throws Exception { + bridge = new DemandForwardingBridge(configuration, createTransport(), createRemoteTransport()); + bridge.setBrokerService(broker); + bridge.setDynamicallyIncludedDestinations(configuration.getDynamicallyIncludedDestinations().toArray( + new ActiveMQDestination[configuration.getDynamicallyIncludedDestinations().size()] + )); + bridge.setExcludedDestinations(configuration.getExcludedDestinations().toArray( + new ActiveMQDestination[configuration.getExcludedDestinations().size()] + )); + bridge.setStaticallyIncludedDestinations(configuration.getStaticallyIncludedDestinations().toArray( + new ActiveMQDestination[configuration.getStaticallyIncludedDestinations().size()] + )); + bridge.start(); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DemandForwardingBridgeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DemandForwardingBridgeTest.java new file mode 100644 index 0000000000..97943379a4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DemandForwardingBridgeTest.java @@ -0,0 +1,177 @@ +/** + * 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.network; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; + +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.util.Wait; + +public class DemandForwardingBridgeTest extends NetworkTestSupport { + + public ActiveMQDestination destination; + public byte destinationType; + public int deliveryMode; + private DemandForwardingBridge bridge; + + public void initCombosForTestSendThenAddConsumer() { + addCombinationValues("deliveryMode", new Object[] {new Integer(DeliveryMode.NON_PERSISTENT), new Integer(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {new Byte(ActiveMQDestination.QUEUE_TYPE)}); + } + + public void testSendThenAddConsumer() throws Exception { + + // Start a producer on local broker + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + // Start a consumer on a remote broker + final StubConnection connection2 = createRemoteConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + + // Send the message to the local broker. + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + + // Verify that the message stayed on the local broker. + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + connection1.send(consumerInfo1); + Message m = receiveMessage(connection1); + assertNotNull(m); + // Close consumer to cause the message to rollback. + connection1.send(consumerInfo1.createRemoveCommand()); + + final DestinationStatistics destinationStatistics = broker.getDestination(destination).getDestinationStatistics(); + assertEquals("broker dest stat dispatched", 1, destinationStatistics.getDispatched().getCount()); + assertEquals("broker dest stat dequeues", 0, destinationStatistics.getDequeues().getCount()); + assertEquals("broker dest stat forwards", 0, destinationStatistics.getForwards().getCount()); + + // Now create remote consumer that should cause message to move to this + // remote consumer. + final ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + connection2.request(consumerInfo2); + + // Make sure the message was delivered via the remote. + assertTrue("message was received", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message msg = receiveMessage(connection2); + if (msg != null) { + connection2.request(createAck(consumerInfo2, msg, 1, MessageAck.STANDARD_ACK_TYPE)); + return true; + } + + return false; + } + })); + + assertTrue("broker dest stat forwards", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 1 == destinationStatistics.getForwards().getCount(); + } + })); + + assertEquals("broker dest stat dequeues", 1, destinationStatistics.getDequeues().getCount()); + } + + public void initCombosForTestAddConsumerThenSend() { + addCombinationValues("deliveryMode", new Object[] {new Integer(DeliveryMode.NON_PERSISTENT), new Integer(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {new Byte(ActiveMQDestination.QUEUE_TYPE), new Byte(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testAddConsumerThenSend() throws Exception { + + // Start a producer on local broker + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + // Start a consumer on a remote broker + StubConnection connection2 = createRemoteConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo2, destination); + connection2.send(consumerInfo); + + // Give demand forwarding bridge a chance to finish forwarding the + // subscriptions. + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + // Send the message to the local boker. + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + // Make sure the message was delivered via the remote. + receiveMessage(connection2); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + NetworkBridgeConfiguration config = new NetworkBridgeConfiguration(); + config.setBrokerName("local"); + config.setDispatchAsync(false); + bridge = new DemandForwardingBridge(config, createTransport(), createRemoteTransport()); + bridge.setBrokerService(broker); + bridge.start(); + } + + @Override + protected void tearDown() throws Exception { + bridge.stop(); + super.tearDown(); + } + + public static Test suite() { + return suite(DemandForwardingBridgeTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkMBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkMBeanTest.java new file mode 100644 index 0000000000..213d4aeb63 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkMBeanTest.java @@ -0,0 +1,171 @@ +/** + * 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.network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeNotNull; + +import java.net.MalformedURLException; +import java.util.Set; + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +import org.apache.activemq.broker.BrokerService; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DuplexNetworkMBeanTest { + + protected static final Logger LOG = LoggerFactory.getLogger(DuplexNetworkMBeanTest.class); + protected final int numRestarts = 3; + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker"); + broker.addConnector("tcp://localhost:61617?transport.reuseAddress=true"); + + return broker; + } + + protected BrokerService createNetworkedBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("networkedBroker"); + broker.addConnector("tcp://localhost:62617?transport.reuseAddress=true"); + NetworkConnector networkConnector = broker.addNetworkConnector("static:(tcp://localhost:61617?wireFormat.maxInactivityDuration=500)?useExponentialBackOff=false"); + networkConnector.setDuplex(true); + return broker; + } + + @Test + public void testMbeanPresenceOnNetworkBrokerRestart() throws Exception { + BrokerService broker = createBroker(); + try { + broker.start(); + assertEquals(1, countMbeans(broker, "connector", 30000)); + assertEquals(0, countMbeans(broker, "connectionName")); + BrokerService networkedBroker = null; + for (int i=0; i mbeans = null; + int count = 0; + do { + if (timeout > 0) { + Thread.sleep(100); + } + + LOG.info("Query name: " + beanName); + mbeans = broker.getManagementContext().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) { + assumeNotNull(mbeans); + } + + return count; + } + + private void logAllMbeans(BrokerService broker) throws MalformedURLException { + try { + // trace all existing MBeans + Set all = broker.getManagementContext().queryNames(null, null); + LOG.info("Total MBean count=" + all.size()); + for (Object o : all) { + ObjectInstance bean = (ObjectInstance)o; + LOG.info(bean.getObjectName().toString()); + } + } catch (Exception ignored) { + LOG.warn("getMBeanServer ex: " + ignored); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkTest.java new file mode 100644 index 0000000000..3afa7d13f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkTest.java @@ -0,0 +1,60 @@ +/** + * 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.network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import javax.jms.MessageProducer; +import javax.jms.TemporaryQueue; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; +import org.junit.Test; + +public class DuplexNetworkTest extends SimpleNetworkTest { + + @Override + protected String getLocalBrokerURI() { + return "org/apache/activemq/network/duplexLocalBroker.xml"; + } + + @Override + protected BrokerService createRemoteBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("remoteBroker"); + broker.addConnector("tcp://localhost:61617"); + return broker; + } + + @Test + public void testTempQueues() throws Exception { + TemporaryQueue temp = localSession.createTemporaryQueue(); + MessageProducer producer = localSession.createProducer(temp); + producer.send(localSession.createTextMessage("test")); + Thread.sleep(100); + assertEquals("Destination not created", 1, remoteBroker.getAdminView().getTemporaryQueues().length); + temp.delete(); + + assertTrue("Destination not deleted", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == remoteBroker.getAdminView().getTemporaryQueues().length; + } + })); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DynamicallyIncludedDestinationsDuplexNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DynamicallyIncludedDestinationsDuplexNetworkTest.java new file mode 100644 index 0000000000..3dd8be6c41 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/DynamicallyIncludedDestinationsDuplexNetworkTest.java @@ -0,0 +1,117 @@ +/** + * 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.network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +import java.lang.reflect.Field; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.jms.MessageProducer; +import javax.jms.TemporaryQueue; + +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnection; +import org.apache.activemq.broker.TransportConnector; +import org.junit.Test; + +/** + * @author Christian Posta + */ +public class DynamicallyIncludedDestinationsDuplexNetworkTest extends SimpleNetworkTest { + + private static final int REMOTE_BROKER_TCP_PORT = 61617; + + @Override + protected String getLocalBrokerURI() { + return "org/apache/activemq/network/duplexDynamicIncludedDestLocalBroker.xml"; + } + + @Override + protected BrokerService createRemoteBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("remoteBroker"); + broker.addConnector("tcp://localhost:" + REMOTE_BROKER_TCP_PORT); + return broker; + } + + // we have to override this, because with dynamicallyIncludedDestinations working properly + // (see https://issues.apache.org/jira/browse/AMQ-4209) you can't get request/response + // with temps working (there is no wild card like there is for staticallyIncludedDest) + // + @Override + public void testRequestReply() throws Exception { + + } + + @Test + public void testTempQueues() throws Exception { + TemporaryQueue temp = localSession.createTemporaryQueue(); + MessageProducer producer = localSession.createProducer(temp); + producer.send(localSession.createTextMessage("test")); + Thread.sleep(100); + assertEquals("Destination not created", 1, remoteBroker.getAdminView().getTemporaryQueues().length); + temp.delete(); + Thread.sleep(100); + assertEquals("Destination not deleted", 0, remoteBroker.getAdminView().getTemporaryQueues().length); + } + + @Test + public void testDynamicallyIncludedDestinationsForDuplex() throws Exception{ + // Once the bridge is set up, we should see the filter used for the duplex end of the bridge + // only subscribe to the specific destinations included in the list + // so let's test that the filter is correct, let's also test the subscription on the localbroker + // is correct + + // the bridge on the remote broker has the correct filter + TransportConnection bridgeConnection = getDuplexBridgeConnectionFromRemote(); + assertNotNull(bridgeConnection); + DemandForwardingBridge duplexBridge = getDuplexBridgeFromConnection(bridgeConnection); + assertNotNull(duplexBridge); + NetworkBridgeConfiguration configuration = getConfigurationFromNetworkBridge(duplexBridge); + assertNotNull(configuration); + assertFalse("This destinationFilter does not include ONLY the destinations specified in dynamicallyIncludedDestinations", + configuration.getDestinationFilter().equals(AdvisorySupport.CONSUMER_ADVISORY_TOPIC_PREFIX + ">")); + assertEquals("There are other patterns in the destinationFilter that shouldn't be there", + "ActiveMQ.Advisory.Consumer.Queue.include.test.foo,ActiveMQ.Advisory.Consumer.Topic.include.test.bar", + configuration.getDestinationFilter()); + } + + private NetworkBridgeConfiguration getConfigurationFromNetworkBridge(DemandForwardingBridgeSupport duplexBridge) throws NoSuchFieldException, IllegalAccessException { + Field f = DemandForwardingBridgeSupport.class.getDeclaredField("configuration"); + f.setAccessible(true); + NetworkBridgeConfiguration configuration = (NetworkBridgeConfiguration) f.get(duplexBridge); + return configuration; + } + + private DemandForwardingBridge getDuplexBridgeFromConnection(TransportConnection bridgeConnection) throws NoSuchFieldException, IllegalAccessException { + Field f = TransportConnection.class.getDeclaredField("duplexBridge"); + f.setAccessible(true); + DemandForwardingBridge bridge = (DemandForwardingBridge) f.get(bridgeConnection); + return bridge; + } + + public TransportConnection getDuplexBridgeConnectionFromRemote() { + TransportConnector transportConnector = remoteBroker.getTransportConnectorByScheme("tcp"); + CopyOnWriteArrayList transportConnections = transportConnector.getConnections(); + TransportConnection duplexBridgeConnectionFromRemote = transportConnections.get(0); + return duplexBridgeConnectionFromRemote; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/FailoverStaticNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/FailoverStaticNetworkTest.java new file mode 100644 index 0000000000..4113f14c44 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/FailoverStaticNetworkTest.java @@ -0,0 +1,467 @@ +/** + * 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.network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Vector; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.management.ObjectName; +import javax.net.ssl.KeyManager; +import javax.net.ssl.TrustManager; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.SslContext; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.transport.tcp.SslBrokerServiceTest; +import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.JMXSupport; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FailoverStaticNetworkTest { + protected static final Logger LOG = LoggerFactory.getLogger(FailoverStaticNetworkTest.class); + + private final static String DESTINATION_NAME = "testQ"; + protected BrokerService brokerA; + protected BrokerService brokerA1; + protected BrokerService brokerB; + protected BrokerService brokerC; + + + private SslContext sslContext; + + protected BrokerService createBroker(String scheme, String listenPort, String[] networkToPorts) throws Exception { + return createBroker(scheme, listenPort, networkToPorts, null); + } + + protected BrokerService createBroker(String scheme, String listenPort, String[] networkToPorts, + HashMap networkProps) throws Exception { + BrokerService broker = new BrokerService(); + broker.getManagementContext().setCreateConnector(false); + broker.setSslContext(sslContext); + broker.setDeleteAllMessagesOnStartup(true); + broker.setBrokerName("Broker_" + listenPort); + // lazy init listener on broker start + TransportConnector transportConnector = new TransportConnector(); + transportConnector.setUri(new URI(scheme + "://localhost:" + listenPort)); + List transportConnectors = new ArrayList(); + transportConnectors.add(transportConnector); + broker.setTransportConnectors(transportConnectors); + if (networkToPorts != null && networkToPorts.length > 0) { + StringBuilder builder = new StringBuilder("static:(failover:(" + scheme + "://localhost:"); + builder.append(networkToPorts[0]); + for (int i=1;i bridgeNames = getNetworkBridgeMBeanName(brokerB); + assertEquals("only one bridgeName: " + bridgeNames, 1, bridgeNames.size()); + + LOG.info("stopping brokerA"); + brokerA.stop(); + brokerA.waitUntilStopped(); + + LOG.info("restarting brokerA"); + brokerA = createBroker("tcp", "63617", null); + brokerA.start(); + + doTestNetworkSendReceive(); + + Set otherBridgeNames = getNetworkBridgeMBeanName(brokerB); + assertEquals("only one bridgeName: " + otherBridgeNames, 1, otherBridgeNames.size()); + + assertTrue("there was an addition", bridgeNames.addAll(otherBridgeNames)); + } + + private Set getNetworkBridgeMBeanName(BrokerService brokerB) throws Exception { + Set names = new HashSet(); + for (ObjectName objectName : brokerB.getManagementContext().queryNames(null, null)) { + if (objectName.getKeyProperty("networkBridge") != null) { + names.add(objectName.getKeyProperty("networkBridge")); + } + } + return names; + } + + @Test + public void testSendReceiveFailoverDuplex() throws Exception { + final Vector errors = new Vector(); + final String dataDir = "target/data/shared"; + brokerA = createBroker("61617", dataDir); + brokerA.start(); + + final BrokerService slave = createBroker("63617", dataDir); + brokerA1 = slave; + ExecutorService executor = Executors.newCachedThreadPool(); + executor.execute(new Runnable() { + @Override + public void run() { + try { + slave.start(); + } catch (Exception e) { + e.printStackTrace(); + errors.add(e); + } + } + }); + executor.shutdown(); + + HashMap networkConnectorProps = new HashMap(); + networkConnectorProps.put("duplex", "true"); + brokerB = createBroker("tcp", "62617", new String[]{"61617", "63617"}, networkConnectorProps); + brokerB.start(); + + doTestNetworkSendReceive(brokerA, brokerB); + doTestNetworkSendReceive(brokerB, brokerA); + + LOG.info("stopping brokerA (master shared_broker)"); + brokerA.stop(); + brokerA.waitUntilStopped(); + + // wait for slave to start + brokerA1.waitUntilStarted(); + + doTestNetworkSendReceive(brokerA1, brokerB); + doTestNetworkSendReceive(brokerB, brokerA1); + + assertTrue("No unexpected exceptions " + errors, errors.isEmpty()); + } + + @Test + // master slave piggy in the middle setup + public void testSendReceiveFailoverDuplexWithPIM() throws Exception { + final String dataDir = "target/data/shared/pim"; + brokerA = createBroker("61617", dataDir); + brokerA.start(); + + final BrokerService slave = createBroker("63617", dataDir); + brokerA1 = slave; + ExecutorService executor = Executors.newCachedThreadPool(); + executor.execute(new Runnable() { + @Override + public void run() { + try { + slave.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + executor.shutdown(); + + HashMap networkConnectorProps = new HashMap(); + networkConnectorProps.put("duplex", "true"); + networkConnectorProps.put("networkTTL", "2"); + + brokerB = createBroker("tcp", "62617", new String[]{"61617", "63617"}, networkConnectorProps); + brokerB.start(); + + assertTrue("all props applied", networkConnectorProps.isEmpty()); + networkConnectorProps.put("duplex", "true"); + networkConnectorProps.put("networkTTL", "2"); + + brokerC = createBroker("tcp", "64617", new String[]{"61617", "63617"}, networkConnectorProps); + brokerC.start(); + assertTrue("all props applied a second time", networkConnectorProps.isEmpty()); + + doTestNetworkSendReceive(brokerC, brokerB); + doTestNetworkSendReceive(brokerB, brokerC); + + LOG.info("stopping brokerA (master shared_broker)"); + brokerA.stop(); + brokerA.waitUntilStopped(); + + doTestNetworkSendReceive(brokerC, brokerB); + doTestNetworkSendReceive(brokerB, brokerC); + + brokerC.stop(); + brokerC.waitUntilStopped(); + } + + /** + * networked broker started after target so first connect attempt succeeds + * start order is important + */ + @Test + public void testSendReceive() throws Exception { + + brokerA = createBroker("tcp", "61617", null); + brokerA.start(); + brokerB = createBroker("tcp", "62617", new String[]{"61617","1111"}); + brokerB.start(); + + doTestNetworkSendReceive(); + } + + @Test + public void testSendReceiveSsl() throws Exception { + + brokerA = createBroker("ssl", "61617", null); + brokerA.start(); + brokerB = createBroker("ssl", "62617", new String[]{"61617", "1111"}); + brokerB.start(); + + doTestNetworkSendReceive(); + } + + @Test + public void testRepeatedSendReceiveWithMasterSlaveAlternate() throws Exception { + doTestRepeatedSendReceiveWithMasterSlaveAlternate(null); + } + + @Test + public void testRepeatedSendReceiveWithMasterSlaveAlternateDuplex() throws Exception { + HashMap networkConnectorProps = new HashMap(); + networkConnectorProps.put("duplex", "true"); + + doTestRepeatedSendReceiveWithMasterSlaveAlternate(networkConnectorProps); + } + + public void doTestRepeatedSendReceiveWithMasterSlaveAlternate(HashMap networkConnectorProps) throws Exception { + + brokerB = createBroker("tcp", "62617", new String[]{"61610","61611"}, networkConnectorProps); + brokerB.start(); + + final AtomicBoolean done = new AtomicBoolean(false); + ExecutorService executorService = Executors.newCachedThreadPool(); + executorService.execute(new Runnable() { + @Override + public void run() { + try { + while (!done.get()) { + brokerA = createBroker("tcp", "61610", null); + brokerA.setBrokerName("Pair"); + brokerA.setBrokerObjectName(new ObjectName(brokerA.getManagementContext().getJmxDomainName() + ":" + "BrokerName=" + + JMXSupport.encodeObjectNamePart("A") + "," + "Type=Broker")); + ((KahaDBPersistenceAdapter)brokerA.getPersistenceAdapter()).getLocker().setLockAcquireSleepInterval(1000); + brokerA.start(); + brokerA.waitUntilStopped(); + + // restart after peer taken over + brokerA1.waitUntilStarted(); + } + } catch (Exception ignored) { + LOG.info("A create/start, unexpected: " + ignored, ignored); + } + } + }); + + // start with brokerA as master + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return brokerA != null && brokerA.waitUntilStarted(); + } + }); + + executorService.execute(new Runnable() { + @Override + public void run() { + try { + while (!done.get()) { + brokerA1 = createBroker("tcp", "61611", null); + brokerA1.setBrokerName("Pair"); + // so they can coexist in local jmx we set the object name b/c the brokername identifies the shared store + brokerA1.setBrokerObjectName(new ObjectName(brokerA.getManagementContext().getJmxDomainName() + ":" + "BrokerName=" + + JMXSupport.encodeObjectNamePart("A1") + "," + "Type=Broker")); + ((KahaDBPersistenceAdapter)brokerA1.getPersistenceAdapter()).getLocker().setLockAcquireSleepInterval(1000); + brokerA1.start(); + brokerA1.waitUntilStopped(); + + // restart after peer taken over + brokerA.waitUntilStarted(); + } + } catch (Exception ignored) { + LOG.info("A1 create/start, unexpected: " + ignored, ignored); + } + } + }); + + for (int i=0; i<4; i++) { + BrokerService currentMaster = (i%2 == 0 ? brokerA : brokerA1); + LOG.info("iteration: " + i + ", using: " + currentMaster.getBrokerObjectName().getKeyProperty("BrokerName")); + currentMaster.waitUntilStarted(); + + doTestNetworkSendReceive(brokerB, currentMaster); + + LOG.info("Stopping " + currentMaster.getBrokerObjectName().getKeyProperty("BrokerName")); + currentMaster.stop(); + currentMaster.waitUntilStopped(); + } + + done.set(true); + LOG.info("all done"); + executorService.shutdownNow(); + } + + private void doTestNetworkSendReceive() throws Exception, JMSException { + doTestNetworkSendReceive(brokerB, brokerA); + } + + private void doTestNetworkSendReceive(final BrokerService to, final BrokerService from) throws Exception, JMSException { + + LOG.info("Creating Consumer on the networked broker ..." + from); + + SslContext.setCurrentSslContext(sslContext); + // Create a consumer on brokerA + ConnectionFactory consFactory = createConnectionFactory(from); + Connection consConn = consFactory.createConnection(); + consConn.start(); + Session consSession = consConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQDestination destination = (ActiveMQDestination) consSession.createQueue(DESTINATION_NAME); + final MessageConsumer consumer = consSession.createConsumer(destination); + + LOG.info("publishing to " + to); + + sendMessageTo(destination, to); + + boolean gotMessage = Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = consumer.receive(5000); + LOG.info("from: " + from.getBrokerObjectName().getKeyProperty("BrokerName") + ", received: " + message); + return message != null; + } + }); + try { + consConn.close(); + } catch (JMSException ignored) { + } + assertTrue("consumer on A got message", gotMessage); + } + + private void sendMessageTo(ActiveMQDestination destination, BrokerService brokerService) throws Exception { + ConnectionFactory factory = createConnectionFactory(brokerService); + Connection conn = factory.createConnection(); + conn.start(); + 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); + connectionFactory.setOptimizedMessageDispatch(true); + connectionFactory.setDispatchAsync(false); + connectionFactory.setUseAsyncSend(false); + connectionFactory.setOptimizeAcknowledge(false); + connectionFactory.setAlwaysSyncSend(true); + return connectionFactory; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ForwardingBridgeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ForwardingBridgeTest.java new file mode 100644 index 0000000000..71006e3211 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ForwardingBridgeTest.java @@ -0,0 +1,154 @@ +/** + * 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.network; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; + +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; + +public class ForwardingBridgeTest extends NetworkTestSupport { + + public ActiveMQDestination destination; + public byte destinationType; + public int deliveryMode; + private ForwardingBridge bridge; + + public void initCombosForTestForwardMessageCompressed() { + addCombinationValues("deliveryMode", new Object[] {new Integer(DeliveryMode.NON_PERSISTENT), + new Integer(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {new Byte(ActiveMQDestination.QUEUE_TYPE), + new Byte(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testForwardMessageCompressed() throws Exception { + + bridge.setUseCompression(true); + + // Start a producer on local broker + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + // Start a consumer on a remote broker + StubConnection connection2 = createRemoteConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo2, destination); + connection2.send(consumerInfo); + Thread.sleep(1000); + // Give forwarding bridge a chance to finish setting up + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + // Send the message to the local boker. + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + + // Make sure the message was delivered via the remote. + Message m = receiveMessage(connection2); + assertNotNull(m); + + // Make sure its compressed now + ActiveMQMessage message = (ActiveMQMessage) m; + assertTrue(message.isCompressed()); + } + + public void initCombosForTestAddConsumerThenSend() { + addCombinationValues("deliveryMode", new Object[] {new Integer(DeliveryMode.NON_PERSISTENT), + new Integer(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {new Byte(ActiveMQDestination.QUEUE_TYPE), + new Byte(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testAddConsumerThenSend() throws Exception { + // Start a producer on local broker + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + + // Start a consumer on a remote broker + StubConnection connection2 = createRemoteConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo2, destination); + connection2.send(consumerInfo); + Thread.sleep(1000); + // Give forwarding bridge a chance to finish setting up + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + // Send the message to the local boker. + connection1.send(createMessage(producerInfo, destination, deliveryMode)); + + // Make sure the message was delivered via the remote. + + Message m = receiveMessage(connection2); + assertNotNull(m); + } + + protected void setUp() throws Exception { + super.setUp(); + bridge = new ForwardingBridge(createTransport(), createRemoteTransport()); + bridge.setClientId("local-remote-bridge"); + bridge.setDispatchAsync(false); + bridge.start(); + } + + protected void tearDown() throws Exception { + bridge.stop(); + super.tearDown(); + } + + public static Test suite() { + return suite(ForwardingBridgeTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/MQTTNetworkOfBrokersFailoverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/MQTTNetworkOfBrokersFailoverTest.java new file mode 100644 index 0000000000..928a7a6364 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/MQTTNetworkOfBrokersFailoverTest.java @@ -0,0 +1,254 @@ +/** + * 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.network; + +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.jmx.BrokerViewMBean; +import org.apache.activemq.broker.jmx.DurableSubscriptionViewMBean; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.commons.lang.ArrayUtils; +import org.fusesource.hawtdispatch.Dispatch; +import org.fusesource.mqtt.client.BlockingConnection; +import org.fusesource.mqtt.client.MQTT; +import org.fusesource.mqtt.client.QoS; +import org.fusesource.mqtt.client.Topic; +import org.fusesource.mqtt.client.Tracer; +import org.fusesource.mqtt.codec.MQTTFrame; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by ceposta + * ", config.getDestinationFilter()); + List dests = new ArrayList(); + config.setDynamicallyIncludedDestinations(dests); + assertEquals(AdvisorySupport.CONSUMER_ADVISORY_TOPIC_PREFIX + ">", config.getDestinationFilter()); + dests.add(new ActiveMQQueue("TEST.>")); + dests.add(new ActiveMQTopic("TEST.>")); + dests.add(new ActiveMQTempQueue("TEST.>")); + String prefix = AdvisorySupport.CONSUMER_ADVISORY_TOPIC_PREFIX; + assertEquals(prefix + "Queue.TEST.>," + prefix + "Topic.TEST.>", config.getDestinationFilter()); + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkFailoverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkFailoverTest.java new file mode 100644 index 0000000000..b16dde00b8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkFailoverTest.java @@ -0,0 +1,232 @@ +/** + * 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.network; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.DestinationDoesNotExistException; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.transport.TransportFilter; +import org.apache.activemq.transport.failover.FailoverTransport; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +public class NetworkFailoverTest extends TestCase { + + protected static final int MESSAGE_COUNT = 10; + private static final Logger LOG = LoggerFactory.getLogger(NetworkFailoverTest.class); + + protected AbstractApplicationContext context; + protected Connection localConnection; + protected Connection remoteConnection; + protected BrokerService localBroker; + 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); + + public void testRequestReply() throws Exception { + final MessageProducer remoteProducer = remoteSession.createProducer(null); + MessageConsumer remoteConsumer = remoteSession.createConsumer(included); + remoteConsumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message msg) { + final TextMessage textMsg = (TextMessage)msg; + try { + String payload = "REPLY: " + textMsg.getText() + ", " + textMsg.getJMSMessageID(); + Destination replyTo; + replyTo = msg.getJMSReplyTo(); + textMsg.clearBody(); + textMsg.setText(payload); + LOG.info("*** Sending response: {}", textMsg.getText()); + remoteProducer.send(replyTo, textMsg); + LOG.info("replied with: " + textMsg.getJMSMessageID()); + + } catch (DestinationDoesNotExistException expected) { + // been removed but not yet recreated + replyToNonExistDest.incrementAndGet(); + try { + LOG.info("NED: " + textMsg.getJMSMessageID()); + } catch (JMSException e) { + e.printStackTrace(); + }; + } catch (Exception e) { + LOG.warn("*** Responder listener caught exception: ", e); + e.printStackTrace(); + } + } + }); + + Queue tempQueue = localSession.createTemporaryQueue(); + MessageProducer requestProducer = localSession.createProducer(included); + requestProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + 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(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + LOG.info("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); + int i = 0; + while (MESSAGE_COUNT > roundTripComplete.get() + remoteDLQCount.get() + replyToNonExistDest.get() + && done > System.currentTimeMillis()) { + if ( i < MESSAGE_COUNT) { + String payload = "test msg " + i; + i++; + 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")); + } + TextMessage result = (TextMessage)requestConsumer.receive(5000); + if (result != null) { + LOG.info("Got reply: " + result.getJMSMessageID() + ", " + result.getText()); + roundTripComplete.incrementAndGet(); + } + } + + 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() ); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + doSetUp(true); + } + + @Override + protected void tearDown() throws Exception { + doTearDown(); + super.tearDown(); + } + + protected void doTearDown() throws Exception { + try { + localConnection.close(); + remoteConnection.close(); + } catch(Exception ex) {} + + try { + localBroker.stop(); + } catch(Exception ex) {} + try { + remoteBroker.stop(); + } catch(Exception ex) {} + } + + protected void doSetUp(boolean deleteAllMessages) throws Exception { + + remoteBroker = createRemoteBroker(); + remoteBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); + remoteBroker.setCacheTempDestinations(true); + remoteBroker.start(); + + localBroker = createLocalBroker(); + localBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); + localBroker.setCacheTempDestinations(true); + localBroker.start(); + + String localURI = "tcp://localhost:61616"; + String remoteURI = "tcp://localhost:61617"; + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory("failover:("+localURI+","+remoteURI+")?randomize=false&backup=false&trackMessages=true"); + localConnection = fac.createConnection(); + localConnection.setClientID("local"); + localConnection.start(); + fac = new ActiveMQConnectionFactory("failover:("+remoteURI + ","+localURI+")?randomize=false&backup=false&trackMessages=true"); + fac.setWatchTopicAdvisories(false); + remoteConnection = fac.createConnection(); + remoteConnection.setClientID("remote"); + remoteConnection.start(); + + localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + protected String getRemoteBrokerURI() { + return "org/apache/activemq/network/remoteBroker.xml"; + } + + protected String getLocalBrokerURI() { + return "org/apache/activemq/network/localBroker.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); + factory.afterPropertiesSet(); + BrokerService result = factory.getBroker(); + return result; + } + + protected BrokerService createLocalBroker() throws Exception { + return createBroker(getLocalBrokerURI()); + } + + protected BrokerService createRemoteBroker() throws Exception { + return createBroker(getRemoteBrokerURI()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkLoadTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkLoadTest.java new file mode 100644 index 0000000000..31d2a07941 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkLoadTest.java @@ -0,0 +1,336 @@ +/** + * 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.network; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.NoSubscriptionRecoveryPolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.VMPendingSubscriberMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.usage.SystemUsage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This test case is used to load test store and forwarding between brokers. It sets up + * n brokers to which have a chain of queues which this test consumes and produces to. + * + * If the network bridges gets stuck at any point subsequent queues will not get messages. This test + * samples the production and consumption stats every second and if the flow of messages + * get stuck then this tast fails. The test monitors the flow of messages for 1 min. + * + * @author chirino + */ +public class NetworkLoadTest extends TestCase { + + private static final transient Logger LOG = LoggerFactory.getLogger(NetworkLoadTest.class); + + // How many times do we sample? + private static final long SAMPLES = Integer.parseInt(System.getProperty("SAMPLES", ""+60*1/5)); + // Slower machines might need to make this bigger. + private static final long SAMPLE_DURATION = Integer.parseInt(System.getProperty("SAMPLES_DURATION", "" + 1000 * 5)); + protected static final int BROKER_COUNT = 4; + protected static final int MESSAGE_SIZE = 2000; + String groupId; + + class ForwardingClient { + + private final AtomicLong forwardCounter = new AtomicLong(); + private final Connection toConnection; + private final Connection fromConnection; + + public ForwardingClient(int from, int to) throws JMSException { + toConnection = createConnection(from); + Session toSession = toConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = toSession.createProducer(new ActiveMQQueue("Q"+to)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.setDisableMessageID(true); + + fromConnection = createConnection(from); + Session fromSession = fromConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = fromSession.createConsumer(new ActiveMQQueue("Q"+from)); + + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message msg) { + try { + producer.send(msg); + forwardCounter.incrementAndGet(); + } catch (JMSException e) { + // this is caused by the connection getting closed. + } + } + }); + } + + public void start() throws JMSException { + toConnection.start(); + fromConnection.start(); + } + + public void stop() throws JMSException { + toConnection.stop(); + fromConnection.stop(); + } + + public void close() throws JMSException { + toConnection.close(); + fromConnection.close(); + } + } + + private BrokerService[] brokers; + private ForwardingClient[] forwardingClients; + + + protected void setUp() throws Exception { + groupId = "network-load-test-"+System.currentTimeMillis(); + brokers = new BrokerService[BROKER_COUNT]; + for (int i = 0; i < brokers.length; i++) { + LOG.info("Starting broker: "+i); + brokers[i] = createBroker(i); + brokers[i].start(); + } + + // Wait for the network connection to get setup. + // The wait is exponential since every broker has to connect to every other broker. + Thread.sleep(BROKER_COUNT*BROKER_COUNT*50); + + forwardingClients = new ForwardingClient[BROKER_COUNT-1]; + for (int i = 0; i < forwardingClients.length; i++) { + LOG.info("Starting fowarding client "+i); + forwardingClients[i] = new ForwardingClient(i, i+1); + forwardingClients[i].start(); + } + } + + protected void tearDown() throws Exception { + for (int i = 0; i < forwardingClients.length; i++) { + LOG.info("Stoping fowarding client "+i); + forwardingClients[i].close(); + } + for (int i = 0; i < brokers.length; i++) { + LOG.info("Stoping broker "+i); + brokers[i].stop(); + } + } + + protected Connection createConnection(int brokerId) throws JMSException { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:"+(60000+brokerId)); + connectionFactory.setOptimizedMessageDispatch(true); + connectionFactory.setCopyMessageOnSend(false); + connectionFactory.setUseCompression(false); + connectionFactory.setDispatchAsync(true); + connectionFactory.setUseAsyncSend(false); + connectionFactory.setOptimizeAcknowledge(false); + connectionFactory.setWatchTopicAdvisories(false); + ActiveMQPrefetchPolicy qPrefetchPolicy= new ActiveMQPrefetchPolicy(); + qPrefetchPolicy.setQueuePrefetch(100); + qPrefetchPolicy.setTopicPrefetch(1000); + connectionFactory.setPrefetchPolicy(qPrefetchPolicy); + connectionFactory.setAlwaysSyncSend(true); + return connectionFactory.createConnection(); + } + + protected BrokerService createBroker(int brokerId) throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker-" + brokerId); + broker.setPersistent(false); + broker.setUseJmx(true); + broker.getManagementContext().setCreateConnector(false); + + final SystemUsage memoryManager = new SystemUsage(); + memoryManager.getMemoryUsage().setLimit(1024 * 1024 * 50); // 50 MB + broker.setSystemUsage(memoryManager); + + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setQueue(">"); + entry.setMemoryLimit(1024 * 1024 * 1); // Set to 1 MB + entry.setPendingSubscriberPolicy(new VMPendingSubscriberMessageStoragePolicy()); + entry.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + policyEntries.add(entry); + + // This is to turn of the default behavior of storing topic messages for retroactive consumption + final PolicyEntry topicPolicyEntry = new PolicyEntry(); + topicPolicyEntry.setTopic(">"); + final NoSubscriptionRecoveryPolicy noSubscriptionRecoveryPolicy = new NoSubscriptionRecoveryPolicy(); + topicPolicyEntry.setSubscriptionRecoveryPolicy(noSubscriptionRecoveryPolicy); + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + broker.setDestinationPolicy(policyMap); + + TransportConnector transportConnector = new TransportConnector(); + transportConnector.setUri(new URI("tcp://localhost:"+(60000+brokerId))); + + transportConnector.setDiscoveryUri(new URI("multicast://default?group="+groupId)); + broker.addConnector(transportConnector); + + DiscoveryNetworkConnector networkConnector = new DiscoveryNetworkConnector(); + networkConnector.setUri(new URI("multicast://default?group="+groupId)); + networkConnector.setBridgeTempDestinations(true); + networkConnector.setPrefetchSize(1); + broker.addNetworkConnector(networkConnector); + + return broker; + } + + public void testRequestReply() throws Exception { + + final int to = 0; // Send to the first broker + int from = brokers.length-1; // consume from the last broker.. + + LOG.info("Staring Final Consumer"); + + Connection fromConnection = createConnection(from); + fromConnection.start(); + Session fromSession = fromConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = fromSession.createConsumer(new ActiveMQQueue("Q"+from)); + + final AtomicReference lastMessageReceived = new AtomicReference(); + final AtomicLong producedMessages = new AtomicLong(); + final AtomicLong receivedMessages = new AtomicLong(); + final AtomicBoolean done = new AtomicBoolean(); + + // Setup the consumer.. + consumer.setMessageListener(new MessageListener() { + public void onMessage(Message msg) { + ActiveMQTextMessage m = (ActiveMQTextMessage) msg; + ActiveMQTextMessage last = lastMessageReceived.get(); + if( last!=null ) { + // Some order checking... + if( last.getMessageId().getProducerSequenceId() > m.getMessageId().getProducerSequenceId() ) { + System.out.println("Received an out of order message. Got "+m.getMessageId()+", expected something after "+last.getMessageId()); + } + } + lastMessageReceived.set(m); + receivedMessages.incrementAndGet(); + } + }); + + LOG.info("Staring Initial Producer"); + final Connection toConnection = createConnection(to); + Thread producer = new Thread("Producer") { + @Override + public void run() { + try { + toConnection.start(); + Session toSession = toConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = toSession.createProducer(new ActiveMQQueue("Q"+to)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.setDisableMessageID(true); + + for (int i = 0; !done.get(); i++) { + TextMessage msg = toSession.createTextMessage(createMessageText(i)); + producer.send(msg); + producedMessages.incrementAndGet(); + } + } catch (JMSException e) { + e.printStackTrace(); + } + } + + private String createMessageText(int index) { + StringBuffer buffer = new StringBuffer(MESSAGE_SIZE); + buffer.append(index + " on " + new Date() + " ..."); + if (buffer.length() > MESSAGE_SIZE) { + return buffer.substring(0, MESSAGE_SIZE); + } + for (int i = buffer.length(); i < MESSAGE_SIZE; i++) { + buffer.append(' '); + } + + return buffer.toString(); + } + }; + producer.start(); + + + // Give the forwarding clients a chance to get going and fill the down + // stream broker queues.. + Thread.sleep(BROKER_COUNT*200); + + for (int i = 0; i < SAMPLES; i++) { + + long start = System.currentTimeMillis(); + producedMessages.set(0); + receivedMessages.set(0); + for (int j = 0; j < forwardingClients.length; j++) { + forwardingClients[j].forwardCounter.set(0); + } + + Thread.sleep(SAMPLE_DURATION); + + long end = System.currentTimeMillis(); + long r = receivedMessages.get(); + long p = producedMessages.get(); + + LOG.info("published: " + p + " msgs at " + (p * 1000f / (end - start)) + " msgs/sec, " + "consumed: " + r + " msgs at " + (r * 1000f / (end - start)) + " msgs/sec"); + + StringBuffer fwdingmsg = new StringBuffer(500); + fwdingmsg.append(" forwarding counters: "); + for (int j = 0; j < forwardingClients.length; j++) { + if( j!= 0 ) { + fwdingmsg.append(", "); + } + fwdingmsg.append(forwardingClients[j].forwardCounter.get()); + } + LOG.info(fwdingmsg.toString()); + + // The test is just checking to make sure thaat the producer and consumer does not hang + // due to the network hops take to route the message form the producer to the consumer. + assertTrue("Recieved some messages since last sample", r>0); + assertTrue("Produced some messages since last sample", p>0); + + } + LOG.info("Sample done."); + done.set(true); + // Wait for the producer to finish. + producer.join(1000*5); + toConnection.close(); + fromConnection.close(); + + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkLoopBackTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkLoopBackTest.java new file mode 100644 index 0000000000..62b79b1668 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkLoopBackTest.java @@ -0,0 +1,65 @@ +/** + * 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.network; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.util.Wait; +import org.junit.Test; + +public class NetworkLoopBackTest { + @Test + public void testLoopbackOnDifferentUrlScheme() throws Exception { + final BrokerService brokerServce = new BrokerService(); + brokerServce.setPersistent(false); + + TransportConnector transportConnector = brokerServce.addConnector("nio://0.0.0.0:0"); + // connection filter is bypassed when scheme is different + final NetworkConnector networkConnector = brokerServce.addNetworkConnector("static:(tcp://" + + transportConnector.getConnectUri().getHost() + ":" + transportConnector.getConnectUri().getPort() + ")"); + + brokerServce.start(); + brokerServce.waitUntilStarted(); + + try { + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 1 == networkConnector.bridges.size(); + } + }); + + final DemandForwardingBridgeSupport loopbackBridge = (DemandForwardingBridgeSupport) networkConnector.bridges.elements().nextElement(); + assertTrue("nc started", networkConnector.isStarted()); + + assertTrue("It should get disposed", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return loopbackBridge.getRemoteBroker().isDisposed(); + } + })); + + assertEquals("No peer brokers", 0, brokerServce.getBroker().getPeerBrokerInfos().length); + + } finally { + brokerServce.stop(); + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkReconnectTest.java new file mode 100644 index 0000000000..68376e16a7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkReconnectTest.java @@ -0,0 +1,326 @@ +/** + * 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.network; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.ConsumerEvent; +import org.apache.activemq.advisory.ConsumerEventSource; +import org.apache.activemq.advisory.ConsumerListener; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * These test cases are used to verifiy that network connections get re + * established in all broker restart scenarios. + * + * @author chirino + */ +public class NetworkReconnectTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(NetworkReconnectTest.class); + + private BrokerService producerBroker; + private BrokerService consumerBroker; + private ActiveMQConnectionFactory producerConnectionFactory; + private ActiveMQConnectionFactory consumerConnectionFactory; + private Destination destination; + private ArrayList connections = new ArrayList(); + + public void xtestMultipleProducerBrokerRestarts() throws Exception { + for (int i = 0; i < 10; i++) { + testWithProducerBrokerRestart(); + disposeConsumerConnections(); + } + } + + public void xtestWithoutRestarts() throws Exception { + startProducerBroker(); + startConsumerBroker(); + + MessageConsumer consumer = createConsumer(); + AtomicInteger counter = createConsumerCounter(producerConnectionFactory); + waitForConsumerToArrive(counter); + + String messageId = sendMessage(); + Message message = consumer.receive(1000); + + assertEquals(messageId, message.getJMSMessageID()); + + assertNull(consumer.receiveNoWait()); + + } + + public void testWithProducerBrokerRestart() throws Exception { + startProducerBroker(); + startConsumerBroker(); + + MessageConsumer consumer = createConsumer(); + AtomicInteger counter = createConsumerCounter(producerConnectionFactory); + waitForConsumerToArrive(counter); + + String messageId = sendMessage(); + Message message = consumer.receive(1000); + + assertEquals(messageId, message.getJMSMessageID()); + assertNull(consumer.receiveNoWait()); + + // Restart the first broker... + stopProducerBroker(); + startProducerBroker(); + + counter = createConsumerCounter(producerConnectionFactory); + waitForConsumerToArrive(counter); + + messageId = sendMessage(); + message = consumer.receive(1000); + + assertEquals(messageId, message.getJMSMessageID()); + assertNull(consumer.receiveNoWait()); + + } + + public void xtestWithConsumerBrokerRestart() throws Exception { + + startProducerBroker(); + startConsumerBroker(); + + MessageConsumer consumer = createConsumer(); + AtomicInteger counter = createConsumerCounter(producerConnectionFactory); + waitForConsumerToArrive(counter); + + String messageId = sendMessage(); + Message message = consumer.receive(1000); + + assertEquals(messageId, message.getJMSMessageID()); + assertNull(consumer.receiveNoWait()); + + // Restart the first broker... + stopConsumerBroker(); + waitForConsumerToLeave(counter); + startConsumerBroker(); + + consumer = createConsumer(); + waitForConsumerToArrive(counter); + + messageId = sendMessage(); + message = consumer.receive(1000); + + assertEquals(messageId, message.getJMSMessageID()); + assertNull(consumer.receiveNoWait()); + + } + + public void xtestWithConsumerBrokerStartDelay() throws Exception { + + startConsumerBroker(); + MessageConsumer consumer = createConsumer(); + + Thread.sleep(1000 * 5); + + startProducerBroker(); + AtomicInteger counter = createConsumerCounter(producerConnectionFactory); + waitForConsumerToArrive(counter); + + String messageId = sendMessage(); + Message message = consumer.receive(1000); + + assertEquals(messageId, message.getJMSMessageID()); + + assertNull(consumer.receiveNoWait()); + + } + + public void xtestWithProducerBrokerStartDelay() throws Exception { + + startProducerBroker(); + AtomicInteger counter = createConsumerCounter(producerConnectionFactory); + + Thread.sleep(1000 * 5); + + startConsumerBroker(); + MessageConsumer consumer = createConsumer(); + + waitForConsumerToArrive(counter); + + String messageId = sendMessage(); + Message message = consumer.receive(1000); + + assertEquals(messageId, message.getJMSMessageID()); + + assertNull(consumer.receiveNoWait()); + + } + + protected void setUp() throws Exception { + + LOG.info("==============================================================================="); + LOG.info("Running Test Case: " + getName()); + LOG.info("==============================================================================="); + + producerConnectionFactory = createProducerConnectionFactory(); + consumerConnectionFactory = createConsumerConnectionFactory(); + destination = new ActiveMQQueue("RECONNECT.TEST.QUEUE"); + + } + + protected void tearDown() throws Exception { + disposeConsumerConnections(); + try { + stopProducerBroker(); + } catch (Throwable e) { + } + try { + stopConsumerBroker(); + } catch (Throwable e) { + } + } + + protected void disposeConsumerConnections() { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection connection = iter.next(); + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected void startProducerBroker() throws Exception { + if (producerBroker == null) { + producerBroker = createFirstBroker(); + producerBroker.start(); + } + } + + protected void stopProducerBroker() throws Exception { + if (producerBroker != null) { + producerBroker.stop(); + producerBroker = null; + } + } + + protected void startConsumerBroker() throws Exception { + if (consumerBroker == null) { + consumerBroker = createSecondBroker(); + consumerBroker.start(); + } + } + + protected void stopConsumerBroker() throws Exception { + if (consumerBroker != null) { + consumerBroker.stop(); + consumerBroker = null; + } + } + + protected BrokerService createFirstBroker() throws Exception { + return BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/network/reconnect-broker1.xml")); + } + + protected BrokerService createSecondBroker() throws Exception { + return BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/network/reconnect-broker2.xml")); + } + + protected ActiveMQConnectionFactory createProducerConnectionFactory() { + return new ActiveMQConnectionFactory("vm://broker1"); + } + + protected ActiveMQConnectionFactory createConsumerConnectionFactory() { + return new ActiveMQConnectionFactory("vm://broker2"); + } + + protected String sendMessage() throws JMSException { + Connection connection = null; + try { + connection = producerConnectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + Message message = session.createMessage(); + producer.send(message); + return message.getJMSMessageID(); + } finally { + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected MessageConsumer createConsumer() throws JMSException { + Connection connection = consumerConnectionFactory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session.createConsumer(destination); + } + + protected AtomicInteger createConsumerCounter(ActiveMQConnectionFactory cf) throws Exception { + final AtomicInteger rc = new AtomicInteger(0); + Connection connection = cf.createConnection(); + connections.add(connection); + connection.start(); + + ConsumerEventSource source = new ConsumerEventSource(connection, destination); + source.setConsumerListener(new ConsumerListener() { + public void onConsumerEvent(ConsumerEvent event) { + rc.set(event.getConsumerCount()); + } + }); + source.start(); + + return rc; + } + + protected void waitForConsumerToArrive(AtomicInteger consumerCounter) throws InterruptedException { + for (int i = 0; i < 100; i++) { + if (consumerCounter.get() > 0) { + return; + } + Thread.sleep(100); + } + fail("The consumer did not arrive."); + } + + protected void waitForConsumerToLeave(AtomicInteger consumerCounter) throws InterruptedException { + for (int i = 0; i < 100; i++) { + if (consumerCounter.get() == 0) { + return; + } + Thread.sleep(100); + } + fail("The consumer did not leave."); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRemovesSubscriptionsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRemovesSubscriptionsTest.java new file mode 100644 index 0000000000..b444379877 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRemovesSubscriptionsTest.java @@ -0,0 +1,190 @@ +/** + * 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.network; + +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQTopic; + +/** + * Various Tests to show the memory leak suspect in network of brokers. This is + * for https://issues.apache.org/activemq/browse/AMQ-2530 + * + */ +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 BrokerService frontEnd; + private BrokerService backEnd; + private final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(frontEndAddress); + private final ActiveMQTopic topic = new ActiveMQTopic(TOPIC_NAME); + + public void testWithSessionAndSubsciberClose() throws Exception { + + 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); + subscriber.close(); + subscriberSession.close(); + } + connection.close(); + Thread.sleep(1000); + Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); + assertNotNull(dest); + assertTrue(dest.getConsumers().isEmpty()); + } + + public void testWithSessionCloseOutsideTheLoop() throws Exception { + + TopicConnection connection = connectionFactory.createTopicConnection(); + connection.start(); + 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); + subscriber.close(); + } + subscriberSession.close(); + connection.close(); + Thread.sleep(1000); + Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); + assertNotNull(dest); + assertTrue(dest.getConsumers().isEmpty()); + + } + + public void testWithOneSubscriber() throws Exception { + + TopicConnection connection = connectionFactory.createTopicConnection(); + connection.start(); + TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + + TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); + DummyMessageListener listener = new DummyMessageListener(); + subscriber.setMessageListener(listener); + subscriber.close(); + subscriberSession.close(); + connection.close(); + Thread.sleep(1000); + Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); + assertNotNull(dest); + assertTrue(dest.getConsumers().isEmpty()); + } + + public void testWithoutSessionAndSubsciberClose() throws Exception { + + 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); + assertNotNull(subscriber); + } + + connection.close(); + Thread.sleep(1000); + Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); + assertNotNull(dest); + assertTrue(dest.getConsumers().isEmpty()); + } + + /** + * Running this test you can produce a leak of only 2 ConsumerInfo on BE + * broker, NOT 200 as in other cases! + * + */ + public void testWithoutSessionAndSubsciberClosePlayAround() throws Exception { + + 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); + if (i != 50) { + subscriber.close(); + subscriberSession.close(); + } + } + + connection.close(); + Thread.sleep(1000); + Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); + assertNotNull(dest); + assertTrue(dest.getConsumers().isEmpty()); + } + + class DummyMessageListener implements MessageListener { + + @Override + public void onMessage(Message arg0) { + // TODO Auto-generated method stub + + } + } + + @Override + 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); + this.backEnd.start(); + + 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); + this.frontEnd.start(); + Thread.sleep(2000); + } + + @Override + protected void tearDown() throws Exception { + if (this.backEnd != null) { + this.backEnd.stop(); + } + if (this.frontEnd != null) { + this.frontEnd.stop(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartPlainTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartPlainTest.java new file mode 100644 index 0000000000..79f15f863e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartPlainTest.java @@ -0,0 +1,24 @@ +/** + * 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.network; + +public class NetworkRestartPlainTest extends NetworkRestartTest { + @Override + protected String getLocalBrokerURI() { + return "org/apache/activemq/network/localBroker-plain.xml"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartTest.java new file mode 100644 index 0000000000..2449fc01b8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartTest.java @@ -0,0 +1,187 @@ +/** + * 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.network; + +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import javax.jms.*; + +public class NetworkRestartTest extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(NetworkRestartTest.class); + + protected Connection localConnection; + protected Connection remoteConnection; + protected BrokerService localBroker; + protected BrokerService remoteBroker; + protected Session localSession; + protected Session remoteSession; + + protected ActiveMQQueue included=new ActiveMQQueue("include.test.foo"); + + + public void testConnectorRestart() throws Exception { + MessageConsumer remoteConsumer = remoteSession.createConsumer(included); + MessageProducer localProducer = localSession.createProducer(included); + + localProducer.send(localSession.createTextMessage("before")); + Message before = remoteConsumer.receive(1000); + assertNotNull(before); + assertEquals("before", ((TextMessage)before).getText()); + + // restart connector + + // wait for ack back to localbroker with concurrent store and dispatch, dispatch occurs first + Thread.sleep(1000); + + NetworkConnector connector = localBroker.getNetworkConnectorByName("networkConnector"); + + LOG.info("Stopping connector"); + connector.stop(); + + Thread.sleep(5000); + LOG.info("Starting connector"); + connector.start(); + + Thread.sleep(5000); + + + localProducer.send(localSession.createTextMessage("after")); + Message after = remoteConsumer.receive(3000); + assertNotNull(after); + assertEquals("after", ((TextMessage)after).getText()); + + } + + public void testConnectorReAdd() throws Exception { + MessageConsumer remoteConsumer = remoteSession.createConsumer(included); + MessageProducer localProducer = localSession.createProducer(included); + + localProducer.send(localSession.createTextMessage("before")); + Message before = remoteConsumer.receive(1000); + assertNotNull(before); + assertEquals("before", ((TextMessage)before).getText()); + + // restart connector + + // wait for ack back to localbroker with concurrent store and dispatch, dispatch occurs first + Thread.sleep(1000); + + NetworkConnector connector = localBroker.getNetworkConnectorByName("networkConnector"); + + LOG.info("Removing connector"); + connector.stop(); + localBroker.removeNetworkConnector(connector); + + Thread.sleep(5000); + LOG.info("Re-adding connector"); + localBroker.addNetworkConnector(connector); + connector.start(); + + Thread.sleep(5000); + + + localProducer.send(localSession.createTextMessage("after")); + Message after = remoteConsumer.receive(3000); + assertNotNull(after); + assertEquals("after", ((TextMessage)after).getText()); + } + + + protected void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + doSetUp(); + } + + protected void tearDown() throws Exception { + localBroker.deleteAllMessages(); + remoteBroker.deleteAllMessages(); + doTearDown(); + super.tearDown(); + } + + protected void doTearDown() throws Exception { + localConnection.close(); + remoteConnection.close(); + localBroker.stop(); + localBroker.waitUntilStopped(); + remoteBroker.stop(); + remoteBroker.waitUntilStopped(); + } + + protected void doSetUp() throws Exception { + + remoteBroker = createRemoteBroker(); + remoteBroker.start(); + remoteBroker.waitUntilStarted(); + localBroker = createLocalBroker(); + localBroker.start(); + localBroker.waitUntilStarted(); + + String localURI = "tcp://localhost:61616"; + String remoteURI = "tcp://localhost:61617"; + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(localURI); + localConnection = fac.createConnection(); + localConnection.setClientID("local"); + localConnection.start(); + + fac = new ActiveMQConnectionFactory(remoteURI); + fac.setWatchTopicAdvisories(false); + remoteConnection = fac.createConnection(); + remoteConnection.setClientID("remote"); + remoteConnection.start(); + + localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + protected String getRemoteBrokerURI() { + return "org/apache/activemq/network/remoteBroker.xml"; + } + + protected String getLocalBrokerURI() { + return "org/apache/activemq/network/localBroker.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); + factory.afterPropertiesSet(); + BrokerService result = factory.getBroker(); + return result; + } + + protected BrokerService createLocalBroker() throws Exception { + return createBroker(getLocalBrokerURI()); + } + + protected BrokerService createRemoteBroker() throws Exception { + return createBroker(getRemoteBrokerURI()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRouteTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRouteTest.java new file mode 100644 index 0000000000..4cd97b0cbc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkRouteTest.java @@ -0,0 +1,346 @@ +/** + * 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.network; + +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageDispatch; +import org.apache.activemq.command.RemoveInfo; +import org.apache.activemq.command.Response; +import org.apache.activemq.command.SessionId; +import org.apache.activemq.transport.FutureResponse; +import org.apache.activemq.transport.ResponseCallback; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportListener; +import org.easymock.EasyMock; +import org.easymock.IAnswer; +import org.easymock.IMocksControl; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class NetworkRouteTest { + private IMocksControl control; + private BrokerService brokerService; + private Transport localBroker; + private Transport remoteBroker; + private TransportListener localListener; + private TransportListener remoteListener; + private MessageDispatch msgDispatch; + private ActiveMQMessage path1Msg; + private ActiveMQMessage path2Msg; + private ActiveMQMessage removePath1Msg; + private ActiveMQMessage removePath2Msg; + + // this sort of mockery is very brittle but it is fast! + + @Test + public void verifyNoRemoveOnOneConduitRemove() throws Exception { + EasyMock.expect(localBroker.request(EasyMock.isA(ConsumerInfo.class))).andReturn(null); + control.replay(); + + remoteListener.onCommand(path2Msg); + remoteListener.onCommand(path1Msg); + + remoteListener.onCommand(removePath2Msg); + control.verify(); + } + + @Test + public void addAndRemoveOppositeOrder() throws Exception { + // from (1) + localBroker.request(EasyMock.isA(ConsumerInfo.class)); + ArgHolder localConsumer = ArgHolder.holdArgsForLastObjectCall(); + // from (2a) + remoteBroker.asyncRequest(EasyMock.isA(ActiveMQMessage.class), EasyMock.isA(ResponseCallback.class)); + ArgHolder firstMessageFuture = ArgHolder.holdArgsForLastFutureRequestCall(); + localBroker.oneway(EasyMock.isA(MessageAck.class)); + // from (2b) + remoteBroker.asyncRequest(EasyMock.isA(ActiveMQMessage.class), EasyMock.isA(ResponseCallback.class)); + ArgHolder secondMessageFuture = ArgHolder.holdArgsForLastFutureRequestCall(); + + localBroker.oneway(EasyMock.isA(MessageAck.class)); + // from (3) + localBroker.oneway(EasyMock.isA(RemoveInfo.class)); + ExpectationWaiter waitForRemove = ExpectationWaiter.waiterForLastVoidCall(); + control.replay(); + + // (1) send advisory of path 1 + remoteListener.onCommand(path1Msg); + msgDispatch.setConsumerId(((ConsumerInfo) localConsumer.arguments[0]).getConsumerId()); + // send advisory of path 2, doesn't send a ConsumerInfo to localBroker + remoteListener.onCommand(path2Msg); + // (2a) send a message + localListener.onCommand(msgDispatch); + ResponseCallback callback = (ResponseCallback) firstMessageFuture.arguments[1]; + FutureResponse response = new FutureResponse(callback); + response.set(new Response()); + + // send advisory of path 2 remove, doesn't send a RemoveInfo to localBroker + remoteListener.onCommand(removePath2Msg); + // (2b) send a message + localListener.onCommand(msgDispatch); + callback = (ResponseCallback) secondMessageFuture.arguments[1]; + response = new FutureResponse(callback); + response.set(new Response()); + + // (3) send advisory of path 1 remove, sends a RemoveInfo to localBroker + remoteListener.onCommand(removePath1Msg); + waitForRemove.assertHappens(5, TimeUnit.SECONDS); + // send a message, does not send message as in 2a and 2b + localListener.onCommand(msgDispatch); + + control.verify(); + } + + @Test + public void addAndRemoveSameOrder() throws Exception { + // from (1) + localBroker.request(EasyMock.isA(ConsumerInfo.class)); + ArgHolder localConsumer = ArgHolder.holdArgsForLastObjectCall(); + + // from (2a) + remoteBroker.asyncRequest(EasyMock.isA(ActiveMQMessage.class), EasyMock.isA(ResponseCallback.class)); + ArgHolder firstMessageFuture = ArgHolder.holdArgsForLastFutureRequestCall(); + + localBroker.oneway(EasyMock.isA(MessageAck.class)); + + // from (2b) + remoteBroker.asyncRequest(EasyMock.isA(ActiveMQMessage.class), EasyMock.isA(ResponseCallback.class)); + ArgHolder secondMessageFuture = ArgHolder.holdArgsForLastFutureRequestCall(); + + localBroker.oneway(EasyMock.isA(MessageAck.class)); + + // from (3) + localBroker.oneway(EasyMock.isA(RemoveInfo.class)); + ExpectationWaiter waitForRemove = ExpectationWaiter.waiterForLastVoidCall(); + control.replay(); + + // (1) send advisory of path 1 + remoteListener.onCommand(path1Msg); + msgDispatch.setConsumerId(((ConsumerInfo) localConsumer.arguments[0]).getConsumerId()); + // send advisory of path 2, doesn't send a ConsumerInfo to localBroker + remoteListener.onCommand(path2Msg); + // (2a) send a message + localListener.onCommand(msgDispatch); + ResponseCallback callback = (ResponseCallback) firstMessageFuture.arguments[1]; + FutureResponse response = new FutureResponse(callback); + response.set(new Response()); + + // send advisory of path 1 remove, shouldn't send a RemoveInfo to localBroker + remoteListener.onCommand(removePath1Msg); + // (2b) send a message, should send the message as in 2a + localListener.onCommand(msgDispatch); + callback = (ResponseCallback) secondMessageFuture.arguments[1]; + response = new FutureResponse(callback); + response.set(new Response()); + + // (3) send advisory of path 1 remove, should send a RemoveInfo to localBroker + remoteListener.onCommand(removePath2Msg); + waitForRemove.assertHappens(5, TimeUnit.SECONDS); + // send a message, does not send message as in 2a + localListener.onCommand(msgDispatch); + + control.verify(); + } + + @Before + public void before() throws Exception { + control = EasyMock.createControl(); + localBroker = control.createMock(Transport.class); + remoteBroker = control.createMock(Transport.class); + + NetworkBridgeConfiguration configuration = new NetworkBridgeConfiguration(); + brokerService = new BrokerService(); + BrokerInfo remoteBrokerInfo = new BrokerInfo(); + + configuration.setDuplex(true); + configuration.setNetworkTTL(5); + brokerService.setBrokerId("broker-1"); + brokerService.setPersistent(false); + brokerService.setUseJmx(false); + brokerService.start(); + brokerService.waitUntilStarted(); + remoteBrokerInfo.setBrokerId(new BrokerId("remote-broker-id")); + remoteBrokerInfo.setBrokerName("remote-broker-name"); + + localBroker.setTransportListener(EasyMock.isA(TransportListener.class)); + ArgHolder localListenerRef = ArgHolder.holdArgsForLastVoidCall(); + + remoteBroker.setTransportListener(EasyMock.isA(TransportListener.class)); + ArgHolder remoteListenerRef = ArgHolder.holdArgsForLastVoidCall(); + localBroker.start(); + remoteBroker.start(); + + remoteBroker.oneway(EasyMock.isA(Object.class)); + EasyMock.expectLastCall().times(4); + remoteBroker.oneway(EasyMock.isA(Object.class)); + ExpectationWaiter remoteInitWaiter = ExpectationWaiter.waiterForLastVoidCall(); + + localBroker.oneway(remoteBrokerInfo); + EasyMock.expect(localBroker.request(EasyMock.isA(Object.class))) + .andReturn(null); + localBroker.oneway(EasyMock.isA(Object.class)); + ExpectationWaiter localInitWaiter = ExpectationWaiter.waiterForLastVoidCall(); + + control.replay(); + + DurableConduitBridge bridge = new DurableConduitBridge(configuration, localBroker, remoteBroker); + bridge.setBrokerService(brokerService); + bridge.start(); + + localListener = (TransportListener) localListenerRef.getArguments()[0]; + Assert.assertNotNull(localListener); + remoteListener = (TransportListener) remoteListenerRef.getArguments()[0]; + Assert.assertNotNull(remoteListener); + + remoteListener.onCommand(remoteBrokerInfo); + + remoteInitWaiter.assertHappens(5, TimeUnit.SECONDS); + localInitWaiter.assertHappens(5, TimeUnit.SECONDS); + + control.verify(); + control.reset(); + + ActiveMQMessage msg = new ActiveMQMessage(); + msg.setDestination(new ActiveMQTopic("test")); + msgDispatch = new MessageDispatch(); + msgDispatch.setMessage(msg); + + ConsumerInfo path1 = new ConsumerInfo(); + path1.setDestination(msg.getDestination()); + path1.setConsumerId(new ConsumerId(new SessionId(new ConnectionId("conn-id-1"), 1), 3)); + path1.setBrokerPath(new BrokerId[]{ + new BrokerId("remote-broker-id"), + new BrokerId("server(1)-broker-id"), + }); + path1Msg = new ActiveMQMessage(); + path1Msg.setDestination(AdvisorySupport.getConsumerAdvisoryTopic(path1.getDestination())); + path1Msg.setDataStructure(path1); + + ConsumerInfo path2 = new ConsumerInfo(); + path2.setDestination(path1.getDestination()); + path2.setConsumerId(new ConsumerId(new SessionId(new ConnectionId("conn-id-2"), 2), 4)); + path2.setBrokerPath(new BrokerId[]{ + new BrokerId("remote-broker-id"), + new BrokerId("server(2)-broker-id"), + new BrokerId("server(1)-broker-id"), + }); + path2Msg = new ActiveMQMessage(); + path2Msg.setDestination(path1Msg.getDestination()); + path2Msg.setDataStructure(path2); + + RemoveInfo removePath1 = new RemoveInfo(path1.getConsumerId()); + RemoveInfo removePath2 = new RemoveInfo(path2.getConsumerId()); + + removePath1Msg = new ActiveMQMessage(); + removePath1Msg.setDestination(path1Msg.getDestination()); + removePath1Msg.setDataStructure(removePath1); + + removePath2Msg = new ActiveMQMessage(); + removePath2Msg.setDestination(path1Msg.getDestination()); + removePath2Msg.setDataStructure(removePath2); + } + + @After + public void after() throws Exception { + control.reset(); + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + private static class ArgHolder { + public Object[] arguments; + + public static ArgHolder holdArgsForLastVoidCall() { + final ArgHolder holder = new ArgHolder(); + EasyMock.expectLastCall().andAnswer(new IAnswer() { + @Override + public Object answer() throws Throwable { + Object[] args = EasyMock.getCurrentArguments(); + holder.arguments = Arrays.copyOf(args, args.length); + return null; + } + }); + return holder; + } + + public static ArgHolder holdArgsForLastObjectCall() { + final ArgHolder holder = new ArgHolder(); + EasyMock.expect(new Object()).andAnswer(new IAnswer() { + @Override + public Object answer() throws Throwable { + Object[] args = EasyMock.getCurrentArguments(); + holder.arguments = Arrays.copyOf(args, args.length); + return null; + } + }); + return holder; + } + + public static ArgHolder holdArgsForLastFutureRequestCall() { + final ArgHolder holder = new ArgHolder(); + EasyMock.expect(new FutureResponse(null)).andAnswer(new IAnswer() { + @Override + public FutureResponse answer() throws Throwable { + Object[] args = EasyMock.getCurrentArguments(); + holder.arguments = Arrays.copyOf(args, args.length); + return null; + } + }); + + return holder; + } + + public Object[] getArguments() { + Assert.assertNotNull(arguments); + return arguments; + } + } + + private static class ExpectationWaiter { + private CountDownLatch latch = new CountDownLatch(1); + + public static ExpectationWaiter waiterForLastVoidCall() { + final ExpectationWaiter waiter = new ExpectationWaiter(); + EasyMock.expectLastCall().andAnswer(new IAnswer() { + @Override + public Object answer() throws Throwable { + waiter.latch.countDown(); + return null; + } + }); + return waiter; + } + + public void assertHappens(long timeout, TimeUnit unit) throws InterruptedException { + Assert.assertTrue(latch.await(timeout, unit)); + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkTestSupport.java new file mode 100644 index 0000000000..6d825a5d69 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/NetworkTestSupport.java @@ -0,0 +1,179 @@ +/** + * 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.network; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTestSupport; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.memory.MemoryPersistenceAdapter; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.usage.SystemUsage; + +public class NetworkTestSupport extends BrokerTestSupport { + + protected ArrayList connections = new ArrayList(); + + protected TransportConnector connector; + + protected PersistenceAdapter remotePersistenceAdapter; + protected BrokerService remoteBroker; + protected SystemUsage remoteMemoryManager; + protected TransportConnector remoteConnector; + protected boolean useJmx = false; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + remotePersistenceAdapter = createRemotePersistenceAdapter(true); + remoteBroker = createRemoteBroker(remotePersistenceAdapter); + remoteConnector = createRemoteConnector(); + remoteBroker.addConnector( remoteConnector ); + BrokerRegistry.getInstance().bind("remotehost", remoteBroker); + remoteBroker.start(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = BrokerFactory.createBroker(new URI("broker:()/localhost?persistent=false&useJmx=false&")); + connector = createConnector(); + broker.addConnector(connector); + broker.setUseJmx(useJmx); + return broker; + } + + /** + * @return + * @throws Exception + * @throws IOException + * @throws URISyntaxException + */ + protected TransportConnector createRemoteConnector() throws Exception, IOException, URISyntaxException { + return new TransportConnector(TransportFactory.bind(new URI(getRemoteURI()))); + } + + /** + * @param value + * @return + * @throws Exception + * @throws IOException + * @throws URISyntaxException + */ + protected TransportConnector createConnector() throws Exception, IOException, URISyntaxException { + return new TransportConnector(TransportFactory.bind(new URI(getLocalURI()))); + } + + protected String getRemoteURI() { + return "vm://remotehost"; + } + + protected String getLocalURI() { + return "vm://localhost"; + } + + protected PersistenceAdapter createRemotePersistenceAdapter(boolean clean) throws Exception { + if (remotePersistenceAdapter == null || clean) { + remotePersistenceAdapter = new MemoryPersistenceAdapter(); + } + return remotePersistenceAdapter; + } + + protected BrokerService createRemoteBroker(PersistenceAdapter persistenceAdapter) throws Exception { + BrokerService answer = new BrokerService(); + answer.setBrokerName("remote"); + answer.setUseJmx(useJmx); + answer.setPersistenceAdapter(persistenceAdapter); + return answer; + } + + @Override + protected StubConnection createConnection() throws Exception { + Transport transport = TransportFactory.connect(connector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + protected StubConnection createRemoteConnection() throws Exception { + Transport transport = TransportFactory.connect(remoteConnector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + protected Transport createTransport() throws Exception { + Transport transport = TransportFactory.connect(connector.getServer().getConnectURI()); + return transport; + } + + protected Transport createRemoteTransport() throws Exception { + Transport transport = TransportFactory.connect(remoteConnector.getServer().getConnectURI()); + return transport; + } + + /** + * Simulates a broker restart. The memory based persistence adapter is + * reused so that it does not "loose" it's "persistent" messages. + * + * @throws Exception + */ + protected void restartRemoteBroker() throws Exception { + + BrokerRegistry.getInstance().unbind("remotehost"); + remoteConnector.stop(); + + remoteBroker.stop(); + remotePersistenceAdapter.stop(); + remotePersistenceAdapter = createRemotePersistenceAdapter(false); + remotePersistenceAdapter.start(); + + remoteBroker = createRemoteBroker(remotePersistenceAdapter); + remoteBroker.addConnector(getRemoteURI()); + remoteBroker.start(); + BrokerRegistry.getInstance().bind("remotehost", remoteBroker); + } + + @Override + protected void tearDown() throws Exception { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + StubConnection connection = iter.next(); + connection.stop(); + iter.remove(); + } + + BrokerRegistry.getInstance().unbind("remotehost"); + remoteConnector.stop(); + connector.stop(); + + remoteBroker.stop(); + remoteBroker.waitUntilStopped(); + remotePersistenceAdapter.stop(); + super.tearDown(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/SSHTunnelNetworkReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/SSHTunnelNetworkReconnectTest.java new file mode 100644 index 0000000000..a7e759bd8b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/SSHTunnelNetworkReconnectTest.java @@ -0,0 +1,94 @@ +/** + * 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.network; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.ArrayList; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; + +/** + * Test network reconnects over SSH tunnels. This case can be especially tricky + * since the SSH tunnels fool the TCP transport into thinking that they are + * initially connected. + * + */ +public class SSHTunnelNetworkReconnectTest extends NetworkReconnectTest { + + ArrayList processes = new ArrayList(); + + @Override + protected BrokerService createFirstBroker() throws Exception { + return BrokerFactory + .createBroker(new URI("xbean:org/apache/activemq/network/ssh-reconnect-broker1.xml")); + } + + @Override + protected BrokerService createSecondBroker() throws Exception { + return BrokerFactory + .createBroker(new URI("xbean:org/apache/activemq/network/ssh-reconnect-broker2.xml")); + } + + @Override + protected void setUp() throws Exception { + startProcess("ssh -Nn -L60006:localhost:61616 localhost"); + startProcess("ssh -Nn -L60007:localhost:61617 localhost"); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + for (Process p : processes) { + p.destroy(); + } + } + + private void startProcess(String command) throws IOException { + final Process process = Runtime.getRuntime().exec(command); + processes.add(process); + new Thread("stdout: " + command) { + @Override + public void run() { + try { + InputStream is = process.getInputStream(); + int c; + while ((c = is.read()) >= 0) { + System.out.write(c); + } + } catch (IOException e) { + } + } + }.start(); + new Thread("stderr: " + command) { + @Override + public void run() { + try { + InputStream is = process.getErrorStream(); + int c; + while ((c = is.read()) >= 0) { + System.err.write(c); + } + } catch (IOException e) { + } + } + }.start(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/SimpleNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/SimpleNetworkTest.java new file mode 100644 index 0000000000..62385cbc89 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/SimpleNetworkTest.java @@ -0,0 +1,322 @@ +/** + * 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.network; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TopicRequestor; +import javax.jms.TopicSession; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.util.Wait; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +public class SimpleNetworkTest { + + protected static final int MESSAGE_COUNT = 10; + private static final Logger LOG = LoggerFactory.getLogger(SimpleNetworkTest.class); + + protected AbstractApplicationContext context; + protected Connection localConnection; + protected Connection remoteConnection; + protected BrokerService localBroker; + protected BrokerService remoteBroker; + protected Session localSession; + protected Session remoteSession; + protected ActiveMQTopic included; + protected ActiveMQTopic excluded; + protected String consumerName = "durableSubs"; + + // works b/c of non marshaling vm transport, the connection + // ref from the client is used during the forward + @Test(timeout = 60 * 1000) + public void testMessageCompression() throws Exception { + + ActiveMQConnection localAmqConnection = (ActiveMQConnection) localConnection; + localAmqConnection.setUseCompression(true); + + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 1, included); + + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message test = localSession.createTextMessage("test-" + i); + producer.send(test); + Message msg = consumer1.receive(3000); + assertNotNull(msg); + ActiveMQMessage amqMessage = (ActiveMQMessage) msg; + assertTrue(amqMessage.isCompressed()); + } + // ensure no more messages received + assertNull(consumer1.receive(1000)); + } + + @Test(timeout = 60 * 1000) + public void testRequestReply() throws Exception { + final MessageProducer remoteProducer = remoteSession.createProducer(null); + MessageConsumer remoteConsumer = remoteSession.createConsumer(included); + remoteConsumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message msg) { + try { + TextMessage textMsg = (TextMessage)msg; + String payload = "REPLY: " + textMsg.getText(); + Destination replyTo; + replyTo = msg.getJMSReplyTo(); + textMsg.clearBody(); + textMsg.setText(payload); + remoteProducer.send(replyTo, textMsg); + } catch (JMSException e) { + e.printStackTrace(); + } + } + }); + + TopicRequestor requestor = new TopicRequestor((TopicSession)localSession, included); + // allow for consumer infos to perculate arround + Thread.sleep(5000); + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage msg = localSession.createTextMessage("test msg: " + i); + TextMessage result = (TextMessage)requestor.request(msg); + assertNotNull(result); + LOG.info(result.getText()); + } + } + + @Test(timeout = 60 * 1000) + public void testFiltering() throws Exception { + MessageConsumer includedConsumer = remoteSession.createConsumer(included); + MessageConsumer excludedConsumer = remoteSession.createConsumer(excluded); + MessageProducer includedProducer = localSession.createProducer(included); + MessageProducer excludedProducer = localSession.createProducer(excluded); + // allow for consumer infos to perculate arround + Thread.sleep(2000); + Message test = localSession.createTextMessage("test"); + includedProducer.send(test); + excludedProducer.send(test); + assertNull(excludedConsumer.receive(1000)); + assertNotNull(includedConsumer.receive(1000)); + } + + @Test(timeout = 60 * 1000) + public void testConduitBridge() throws Exception { + MessageConsumer consumer1 = remoteSession.createConsumer(included); + MessageConsumer consumer2 = remoteSession.createConsumer(included); + MessageProducer producer = localSession.createProducer(included); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + waitForConsumerRegistration(localBroker, 2, included); + + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message test = localSession.createTextMessage("test-" + i); + producer.send(test); + assertNotNull(consumer1.receive(1000)); + assertNotNull(consumer2.receive(1000)); + } + // ensure no more messages received + assertNull(consumer1.receive(1000)); + assertNull(consumer2.receive(1000)); + } + + private void waitForConsumerRegistration(final BrokerService brokerService, final int min, final ActiveMQDestination destination) throws Exception { + assertTrue("Internal bridge consumers registered in time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Object[] bridges = brokerService.getNetworkConnectors().get(0).bridges.values().toArray(); + if (bridges.length > 0) { + LOG.info(brokerService + " bridges " + Arrays.toString(bridges)); + DemandForwardingBridgeSupport demandForwardingBridgeSupport = (DemandForwardingBridgeSupport) bridges[0]; + ConcurrentHashMap forwardingBridges = demandForwardingBridgeSupport.getLocalSubscriptionMap(); + LOG.info(brokerService + " bridge " + demandForwardingBridgeSupport + ", localSubs: " + forwardingBridges); + if (!forwardingBridges.isEmpty()) { + for (DemandSubscription demandSubscription : forwardingBridges.values()) { + if (demandSubscription.getLocalInfo().getDestination().equals(destination)) { + LOG.info(brokerService + " DemandSubscription " + demandSubscription + ", size: " + demandSubscription.size()); + return demandSubscription.size() >= min; + } + } + } + } + return false; + } + })); + } + + @Test(timeout = 60 * 1000) + public void testDurableStoreAndForward() throws Exception { + // create a remote durable consumer + MessageConsumer remoteConsumer = remoteSession.createDurableSubscriber(included, consumerName); + Thread.sleep(1000); + // now close everything down and restart + doTearDown(); + doSetUp(false); + MessageProducer producer = localSession.createProducer(included); + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message test = localSession.createTextMessage("test-" + i); + producer.send(test); + } + Thread.sleep(1000); + // close everything down and restart + doTearDown(); + doSetUp(false); + remoteConsumer = remoteSession.createDurableSubscriber(included, consumerName); + for (int i = 0; i < MESSAGE_COUNT; i++) { + assertNotNull("message count: " + i, remoteConsumer.receive(2500)); + } + } + + @Ignore("This seems like a simple use case, but it is problematic to consume an existing topic store, " + + "it requires a connection per durable to match that connectionId") + public void testDurableStoreAndForwardReconnect() throws Exception { + // create a local durable consumer + MessageConsumer localConsumer = localSession.createDurableSubscriber(included, consumerName); + Thread.sleep(5000); + // now close everything down and restart + doTearDown(); + doSetUp(false); + // send messages + MessageProducer producer = localSession.createProducer(included); + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message test = localSession.createTextMessage("test-" + i); + producer.send(test); + } + Thread.sleep(5000); + // consume some messages locally + localConsumer = localSession.createDurableSubscriber(included, consumerName); + LOG.info("Consume from local consumer: " + localConsumer); + for (int i = 0; i < MESSAGE_COUNT / 2; i++) { + assertNotNull("message count: " + i, localConsumer.receive(2500)); + } + Thread.sleep(5000); + // close everything down and restart + doTearDown(); + doSetUp(false); + Thread.sleep(5000); + + LOG.info("Consume from remote"); + // consume the rest remotely + MessageConsumer remoteConsumer = remoteSession.createDurableSubscriber(included, consumerName); + LOG.info("Remote consumer: " + remoteConsumer); + Thread.sleep(5000); + for (int i = 0; i < MESSAGE_COUNT / 2; i++) { + assertNotNull("message count: " + i, remoteConsumer.receive(10000)); + } + } + + @Before + public void setUp() throws Exception { + doSetUp(true); + } + + @After + public void tearDown() throws Exception { + doTearDown(); + } + + protected void doTearDown() throws Exception { + localConnection.close(); + remoteConnection.close(); + localBroker.stop(); + remoteBroker.stop(); + } + + protected void doSetUp(boolean deleteAllMessages) throws Exception { + remoteBroker = createRemoteBroker(); + remoteBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); + remoteBroker.start(); + remoteBroker.waitUntilStarted(); + localBroker = createLocalBroker(); + localBroker.setDeleteAllMessagesOnStartup(deleteAllMessages); + localBroker.start(); + localBroker.waitUntilStarted(); + URI localURI = localBroker.getVmConnectorURI(); + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(localURI); + fac.setAlwaysSyncSend(true); + fac.setDispatchAsync(false); + localConnection = fac.createConnection(); + localConnection.setClientID("clientId"); + localConnection.start(); + URI remoteURI = remoteBroker.getVmConnectorURI(); + fac = new ActiveMQConnectionFactory(remoteURI); + remoteConnection = fac.createConnection(); + remoteConnection.setClientID("clientId"); + remoteConnection.start(); + included = new ActiveMQTopic("include.test.bar"); + excluded = new ActiveMQTopic("exclude.test.bar"); + localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + protected String getRemoteBrokerURI() { + return "org/apache/activemq/network/remoteBroker.xml"; + } + + protected String getLocalBrokerURI() { + return "org/apache/activemq/network/localBroker.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); + factory.afterPropertiesSet(); + BrokerService result = factory.getBroker(); + return result; + } + + protected BrokerService createLocalBroker() throws Exception { + return createBroker(getLocalBrokerURI()); + } + + protected BrokerService createRemoteBroker() throws Exception { + return createBroker(getRemoteBrokerURI()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/duplexDynamicIncludedDestLocalBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/duplexDynamicIncludedDestLocalBroker.xml new file mode 100644 index 0000000000..70f6da8215 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/duplexDynamicIncludedDestLocalBroker.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/duplexLocalBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/duplexLocalBroker.xml new file mode 100644 index 0000000000..17268c37f1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/duplexLocalBroker.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeStandaloneReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeStandaloneReconnectTest.java new file mode 100644 index 0000000000..c3553f35bc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeStandaloneReconnectTest.java @@ -0,0 +1,370 @@ +/** + * 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.network.jms; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Iterator; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class QueueBridgeStandaloneReconnectTest { + + private SimpleJmsQueueConnector jmsQueueConnector; + + private BrokerService localBroker; + private BrokerService foreignBroker; + + private ActiveMQConnectionFactory localConnectionFactory; + private ActiveMQConnectionFactory foreignConnectionFactory; + + private Destination outbound; + private Destination inbound; + + private final ArrayList connections = new ArrayList(); + + @Test(timeout = 60 * 1000) + public void testSendAndReceiveOverConnectedBridges() throws Exception { + + startLocalBroker(); + startForeignBroker(); + + jmsQueueConnector.start(); + + sendMessageToForeignBroker("to.foreign.broker"); + sendMessageToLocalBroker("to.local.broker"); + + final MessageConsumer local = createConsumerForLocalBroker(); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = local.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.local.broker")) { + return true; + } + return false; + } + })); + + final MessageConsumer foreign = createConsumerForForeignBroker(); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = foreign.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.foreign.broker")) { + return true; + } + return false; + } + })); + } + + @Test(timeout = 60 * 1000) + public void testSendAndReceiveOverBridgeWhenStartedBeforeBrokers() throws Exception { + + jmsQueueConnector.start(); + + startLocalBroker(); + startForeignBroker(); + + assertTrue("Should have Connected.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return jmsQueueConnector.isConnected(); + } + })); + + sendMessageToForeignBroker("to.foreign.broker"); + sendMessageToLocalBroker("to.local.broker"); + + final MessageConsumer local = createConsumerForLocalBroker(); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = local.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.local.broker")) { + return true; + } + return false; + } + })); + + final MessageConsumer foreign = createConsumerForForeignBroker(); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = foreign.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.foreign.broker")) { + return true; + } + return false; + } + })); + } + + @Test(timeout = 60 * 1000) + public void testSendAndReceiveOverBridgeWithRestart() throws Exception { + + startLocalBroker(); + startForeignBroker(); + + jmsQueueConnector.start(); + + assertTrue("Should have Connected.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return jmsQueueConnector.isConnected(); + } + })); + + stopLocalBroker(); + stopForeignBroker(); + + assertTrue("Should have detected connection drop.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return !jmsQueueConnector.isConnected(); + } + })); + + startLocalBroker(); + startForeignBroker(); + + assertTrue("Should have Re-Connected.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return jmsQueueConnector.isConnected(); + } + })); + + sendMessageToForeignBroker("to.foreign.broker"); + sendMessageToLocalBroker("to.local.broker"); + + final MessageConsumer local = createConsumerForLocalBroker(); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = local.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.local.broker")) { + return true; + } + return false; + } + })); + + final MessageConsumer foreign = createConsumerForForeignBroker(); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = foreign.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.foreign.broker")) { + return true; + } + return false; + } + })); + } + + @Before + public void setUp() throws Exception { + + localConnectionFactory = createLocalConnectionFactory(); + foreignConnectionFactory = createForeignConnectionFactory(); + + outbound = new ActiveMQQueue("RECONNECT.TEST.OUT.QUEUE"); + inbound = new ActiveMQQueue("RECONNECT.TEST.IN.QUEUE"); + + jmsQueueConnector = new SimpleJmsQueueConnector(); + + // Wire the bridges. + jmsQueueConnector.setOutboundQueueBridges( + new OutboundQueueBridge[] {new OutboundQueueBridge("RECONNECT.TEST.OUT.QUEUE")}); + jmsQueueConnector.setInboundQueueBridges( + new InboundQueueBridge[] {new InboundQueueBridge("RECONNECT.TEST.IN.QUEUE")}); + + // Tell it how to reach the two brokers. + jmsQueueConnector.setOutboundQueueConnectionFactory( + new ActiveMQConnectionFactory("tcp://localhost:61617")); + jmsQueueConnector.setLocalQueueConnectionFactory( + new ActiveMQConnectionFactory("tcp://localhost:61616")); + } + + @After + public void tearDown() throws Exception { + disposeConsumerConnections(); + + try { + jmsQueueConnector.stop(); + jmsQueueConnector = null; + } catch (Exception e) { + } + + try { + stopLocalBroker(); + } catch (Throwable e) { + } + try { + stopForeignBroker(); + } catch (Throwable e) { + } + } + + protected void disposeConsumerConnections() { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection connection = iter.next(); + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected void startLocalBroker() throws Exception { + if (localBroker == null) { + localBroker = createFirstBroker(); + localBroker.start(); + localBroker.waitUntilStarted(); + } + } + + protected void stopLocalBroker() throws Exception { + if (localBroker != null) { + localBroker.stop(); + localBroker.waitUntilStopped(); + localBroker = null; + } + } + + protected void startForeignBroker() throws Exception { + if (foreignBroker == null) { + foreignBroker = createSecondBroker(); + foreignBroker.start(); + foreignBroker.waitUntilStarted(); + } + } + + protected void stopForeignBroker() throws Exception { + if (foreignBroker != null) { + foreignBroker.stop(); + foreignBroker.waitUntilStopped(); + foreignBroker = null; + } + } + + protected BrokerService createFirstBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker1"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61616"); + + return broker; + } + + protected BrokerService createSecondBroker() throws Exception { + + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker2"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61617"); + + return broker; + } + + protected ActiveMQConnectionFactory createLocalConnectionFactory() { + return new ActiveMQConnectionFactory("tcp://localhost:61616"); + } + + protected ActiveMQConnectionFactory createForeignConnectionFactory() { + return new ActiveMQConnectionFactory("tcp://localhost:61617"); + } + + protected void sendMessageToForeignBroker(String text) throws JMSException { + Connection connection = null; + try { + connection = localConnectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(outbound); + TextMessage message = session.createTextMessage(); + message.setText(text); + producer.send(message); + } finally { + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected void sendMessageToLocalBroker(String text) throws JMSException { + Connection connection = null; + try { + connection = foreignConnectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(inbound); + TextMessage message = session.createTextMessage(); + message.setText(text); + producer.send(message); + } finally { + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected MessageConsumer createConsumerForLocalBroker() throws JMSException { + Connection connection = localConnectionFactory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session.createConsumer(inbound); + } + + protected MessageConsumer createConsumerForForeignBroker() throws JMSException { + Connection connection = foreignConnectionFactory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session.createConsumer(outbound); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeTest.java new file mode 100644 index 0000000000..104e9da9c6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeTest.java @@ -0,0 +1,111 @@ +/** + * 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.network.jms; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueRequestor; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class QueueBridgeTest extends TestCase implements MessageListener { + + protected static final int MESSAGE_COUNT = 10; + private static final Logger LOG = LoggerFactory.getLogger(QueueBridgeTest.class); + + protected AbstractApplicationContext context; + protected QueueConnection localConnection; + protected QueueConnection remoteConnection; + protected QueueRequestor requestor; + protected QueueSession requestServerSession; + protected MessageConsumer requestServerConsumer; + protected MessageProducer requestServerProducer; + + protected void setUp() throws Exception { + super.setUp(); + context = createApplicationContext(); + + createConnections(); + + requestServerSession = localConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + Queue theQueue = requestServerSession.createQueue(getClass().getName()); + requestServerConsumer = requestServerSession.createConsumer(theQueue); + requestServerConsumer.setMessageListener(this); + requestServerProducer = requestServerSession.createProducer(null); + + QueueSession session = remoteConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + requestor = new QueueRequestor(session, theQueue); + } + + protected void createConnections() throws JMSException { + ActiveMQConnectionFactory fac = (ActiveMQConnectionFactory)context.getBean("localFactory"); + localConnection = fac.createQueueConnection(); + localConnection.start(); + + fac = (ActiveMQConnectionFactory)context.getBean("remoteFactory"); + remoteConnection = fac.createQueueConnection(); + remoteConnection.start(); + } + + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/network/jms/queue-config.xml"); + } + + protected void tearDown() throws Exception { + localConnection.close(); + super.tearDown(); + } + + public void testQueueRequestorOverBridge() throws JMSException { + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage msg = requestServerSession.createTextMessage("test msg: " + i); + TextMessage result = (TextMessage)requestor.request(msg); + assertNotNull(result); + LOG.info(result.getText()); + } + } + + public void onMessage(Message msg) { + try { + TextMessage textMsg = (TextMessage)msg; + String payload = "REPLY: " + textMsg.getText(); + Destination replyTo; + replyTo = msg.getJMSReplyTo(); + textMsg.clearBody(); + textMsg.setText(payload); + requestServerProducer.send(replyTo, textMsg); + } catch (JMSException e) { + e.printStackTrace(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeXBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeXBeanTest.java new file mode 100644 index 0000000000..c75747d115 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueBridgeXBeanTest.java @@ -0,0 +1,45 @@ +/** + * 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.network.jms; + +import org.apache.xbean.spring.context.ClassPathXmlApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; + + +/** + * + * + */ +public class QueueBridgeXBeanTest extends QueueBridgeTest { + + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/network/jms/queue-xbean.xml"); + } + + /* + protected void createConnections() throws JMSException { + ActiveMQConnectionFactory fac = (ActiveMQConnectionFactory) context.getBean("localFactory"); + localConnection = fac.createQueueConnection(); + localConnection.start(); + + fac = (ActiveMQConnectionFactory) context.getBean("remoteFactory"); + remoteConnection = fac.createQueueConnection(); + remoteConnection.start(); + } + */ + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueOutboundBridgeReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueOutboundBridgeReconnectTest.java new file mode 100644 index 0000000000..ed0a6fe57f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/QueueOutboundBridgeReconnectTest.java @@ -0,0 +1,345 @@ +/** + * 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.network.jms; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * These test cases are used to verify that queue outbound bridge connections get + * re-established in all broker restart scenarios. This is possible when the + * outbound bridge is configured using the failover URI with a timeout. + */ +public class QueueOutboundBridgeReconnectTest { + + private BrokerService producerBroker; + private BrokerService consumerBroker; + private ActiveMQConnectionFactory producerConnectionFactory; + private ActiveMQConnectionFactory consumerConnectionFactory; + private Destination destination; + private final ArrayList connections = new ArrayList(); + + @Test + public void testMultipleProducerBrokerRestarts() throws Exception { + for (int i = 0; i < 10; i++) { + testWithProducerBrokerRestart(); + disposeConsumerConnections(); + } + } + + @Test + public void testRestartProducerWithNoConsumer() throws Exception { + stopConsumerBroker(); + + startProducerBroker(); + sendMessage("test123"); + sendMessage("test456"); + } + + @Test + public void testWithoutRestartsConsumerFirst() throws Exception { + startConsumerBroker(); + startProducerBroker(); + sendMessage("test123"); + sendMessage("test456"); + + MessageConsumer consumer = createConsumer(); + Message message = consumer.receive(3000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + + message = consumer.receive(3000); + assertNotNull(message); + assertEquals("test456", ((TextMessage)message).getText()); + + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithoutRestartsProducerFirst() throws Exception { + startProducerBroker(); + sendMessage("test123"); + + startConsumerBroker(); + + // unless using a failover URI, the first attempt of this send will likely fail, + // so increase the timeout below to give the bridge time to recover + sendMessage("test456"); + + MessageConsumer consumer = createConsumer(); + Message message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage) message).getText()); + + message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test456", ((TextMessage) message).getText()); + + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithProducerBrokerRestart() throws Exception { + startProducerBroker(); + startConsumerBroker(); + + sendMessage("test123"); + + MessageConsumer consumer = createConsumer(); + Message message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer.receiveNoWait()); + + // Restart the first broker... + stopProducerBroker(); + startProducerBroker(); + + sendMessage("test123"); + message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithConsumerBrokerRestart() throws Exception { + + startProducerBroker(); + startConsumerBroker(); + + sendMessage("test123"); + + final MessageConsumer consumer1 = createConsumer(); + Message message = consumer1.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer1.receiveNoWait()); + consumer1.close(); + + // Restart the first broker... + stopConsumerBroker(); + startConsumerBroker(); + + // unless using a failover URI, the first attempt of this send will likely fail, + // so increase the timeout below to give the bridge time to recover + sendMessage("test123"); + + final MessageConsumer consumer2 = createConsumer(); + assertTrue("Expected recover and delivery failed", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + Message message = consumer2.receiveNoWait(); + if (message == null || !((TextMessage)message).getText().equals("test123")) { + return false; + } + return true; + } + })); + assertNull(consumer2.receiveNoWait()); + } + + @Test + public void testWithConsumerBrokerStartDelay() throws Exception { + + startConsumerBroker(); + final MessageConsumer consumer = createConsumer(); + + TimeUnit.SECONDS.sleep(5); + + startProducerBroker(); + + sendMessage("test123"); + assertTrue("Expected recover and delivery failed", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + Message message = consumer.receiveNoWait(); + if (message == null || !((TextMessage)message).getText().equals("test123")) { + return false; + } + return true; + } + })); + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithProducerBrokerStartDelay() throws Exception { + + startProducerBroker(); + + TimeUnit.SECONDS.sleep(5); + + startConsumerBroker(); + MessageConsumer consumer = createConsumer(); + + sendMessage("test123"); + Message message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer.receiveNoWait()); + } + + @Before + public void setUp() throws Exception { + + producerConnectionFactory = createProducerConnectionFactory(); + consumerConnectionFactory = createConsumerConnectionFactory(); + destination = new ActiveMQQueue("RECONNECT.TEST.QUEUE"); + } + + @After + public void tearDown() throws Exception { + disposeConsumerConnections(); + try { + stopProducerBroker(); + } catch (Throwable e) { + } + try { + stopConsumerBroker(); + } catch (Throwable e) { + } + } + + protected void disposeConsumerConnections() { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection connection = iter.next(); + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected void startProducerBroker() throws Exception { + if (producerBroker == null) { + producerBroker = createFirstBroker(); + producerBroker.start(); + } + } + + protected void stopProducerBroker() throws Exception { + if (producerBroker != null) { + producerBroker.stop(); + producerBroker = null; + } + } + + protected void startConsumerBroker() throws Exception { + if (consumerBroker == null) { + consumerBroker = createSecondBroker(); + consumerBroker.start(); + } + } + + protected void stopConsumerBroker() throws Exception { + if (consumerBroker != null) { + consumerBroker.stop(); + consumerBroker = null; + } + } + + protected BrokerService createFirstBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker1"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61616"); + broker.addConnector("vm://broker1"); + + SimpleJmsQueueConnector jmsQueueConnector = new SimpleJmsQueueConnector(); + jmsQueueConnector.setOutboundQueueBridges( + new OutboundQueueBridge[] {new OutboundQueueBridge("RECONNECT.TEST.QUEUE")}); + jmsQueueConnector.setOutboundQueueConnectionFactory( + new ActiveMQConnectionFactory("tcp://localhost:61617")); + + broker.setJmsBridgeConnectors(new JmsConnector[]{jmsQueueConnector}); + + return broker; + } + + protected BrokerService createSecondBroker() throws Exception { + + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker2"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61617"); + broker.addConnector("vm://broker2"); + + return broker; + } + + protected ActiveMQConnectionFactory createProducerConnectionFactory() { + return new ActiveMQConnectionFactory("vm://broker1"); + } + + protected ActiveMQConnectionFactory createConsumerConnectionFactory() { + return new ActiveMQConnectionFactory("vm://broker2"); + } + + protected void sendMessage(String text) throws JMSException { + Connection connection = null; + try { + connection = producerConnectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage(); + message.setText(text); + producer.send(message); + } finally { + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected MessageConsumer createConsumer() throws JMSException { + Connection connection = consumerConnectionFactory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session.createConsumer(destination); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeSpringTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeSpringTest.java new file mode 100644 index 0000000000..604c496df2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeSpringTest.java @@ -0,0 +1,106 @@ +/** + * 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.network.jms; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicRequestor; +import javax.jms.TopicSession; +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class TopicBridgeSpringTest extends TestCase implements MessageListener { + + protected static final int MESSAGE_COUNT = 10; + private static final Logger LOG = LoggerFactory.getLogger(TopicBridgeSpringTest.class); + + protected AbstractApplicationContext context; + protected TopicConnection localConnection; + protected TopicConnection remoteConnection; + protected TopicRequestor requestor; + protected TopicSession requestServerSession; + protected MessageConsumer requestServerConsumer; + protected MessageProducer requestServerProducer; + + protected void setUp() throws Exception { + + super.setUp(); + context = createApplicationContext(); + ActiveMQConnectionFactory fac = (ActiveMQConnectionFactory)context.getBean("localFactory"); + localConnection = fac.createTopicConnection(); + localConnection.start(); + requestServerSession = localConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + Topic theTopic = requestServerSession.createTopic(getClass().getName()); + requestServerConsumer = requestServerSession.createConsumer(theTopic); + requestServerConsumer.setMessageListener(this); + requestServerProducer = requestServerSession.createProducer(null); + + fac = (ActiveMQConnectionFactory)context.getBean("remoteFactory"); + remoteConnection = fac.createTopicConnection(); + remoteConnection.start(); + TopicSession session = remoteConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + requestor = new TopicRequestor(session, theTopic); + } + + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/network/jms/topic-spring.xml"); + } + + protected void tearDown() throws Exception { + localConnection.close(); + super.tearDown(); + } + + public void testTopicRequestorOverBridge() throws JMSException { + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage msg = requestServerSession.createTextMessage("test msg: " + i); + LOG.info("Making request: " + msg); + TextMessage result = (TextMessage)requestor.request(msg); + assertNotNull(result); + LOG.info("Received result: " + result.getText()); + } + } + + public void onMessage(Message msg) { + try { + TextMessage textMsg = (TextMessage)msg; + String payload = "REPLY: " + textMsg.getText(); + Destination replyTo; + replyTo = msg.getJMSReplyTo(); + textMsg.clearBody(); + textMsg.setText(payload); + LOG.info("Sending response: " + textMsg); + requestServerProducer.send(replyTo, textMsg); + } catch (JMSException e) { + e.printStackTrace(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeStandaloneReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeStandaloneReconnectTest.java new file mode 100644 index 0000000000..c499ff36bc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeStandaloneReconnectTest.java @@ -0,0 +1,367 @@ +/** + * 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.network.jms; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Iterator; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TopicBridgeStandaloneReconnectTest { + + private SimpleJmsTopicConnector jmsTopicConnector; + + private BrokerService localBroker; + private BrokerService foreignBroker; + + private ActiveMQConnectionFactory localConnectionFactory; + private ActiveMQConnectionFactory foreignConnectionFactory; + + private Destination outbound; + private Destination inbound; + + private final ArrayList connections = new ArrayList(); + + @Test + public void testSendAndReceiveOverConnectedBridges() throws Exception { + + startLocalBroker(); + startForeignBroker(); + + jmsTopicConnector.start(); + + final MessageConsumer local = createConsumerForLocalBroker(); + final MessageConsumer foreign = createConsumerForForeignBroker(); + + sendMessageToForeignBroker("to.foreign.broker"); + sendMessageToLocalBroker("to.local.broker"); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = local.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.local.broker")) { + return true; + } + return false; + } + })); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = foreign.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.foreign.broker")) { + return true; + } + return false; + } + })); + } + + @Test + public void testSendAndReceiveOverBridgeWhenStartedBeforeBrokers() throws Exception { + + jmsTopicConnector.start(); + + startLocalBroker(); + startForeignBroker(); + + assertTrue("Should have Connected.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return jmsTopicConnector.isConnected(); + } + })); + + final MessageConsumer local = createConsumerForLocalBroker(); + final MessageConsumer foreign = createConsumerForForeignBroker(); + + sendMessageToForeignBroker("to.foreign.broker"); + sendMessageToLocalBroker("to.local.broker"); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = local.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.local.broker")) { + return true; + } + return false; + } + })); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = foreign.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.foreign.broker")) { + return true; + } + return false; + } + })); + } + + @Test + public void testSendAndReceiveOverBridgeWithRestart() throws Exception { + + startLocalBroker(); + startForeignBroker(); + + jmsTopicConnector.start(); + + assertTrue("Should have Connected.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return jmsTopicConnector.isConnected(); + } + })); + + stopLocalBroker(); + stopForeignBroker(); + + assertTrue("Should have detected connection drop.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return !jmsTopicConnector.isConnected(); + } + })); + + startLocalBroker(); + startForeignBroker(); + + assertTrue("Should have Re-Connected.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return jmsTopicConnector.isConnected(); + } + })); + + final MessageConsumer local = createConsumerForLocalBroker(); + final MessageConsumer foreign = createConsumerForForeignBroker(); + + sendMessageToForeignBroker("to.foreign.broker"); + sendMessageToLocalBroker("to.local.broker"); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = local.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.local.broker")) { + return true; + } + return false; + } + })); + + assertTrue("Should have received a Message.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Message message = foreign.receive(100); + if (message != null && ((TextMessage) message).getText().equals("to.foreign.broker")) { + return true; + } + return false; + } + })); + } + + @Before + public void setUp() throws Exception { + + localConnectionFactory = createLocalConnectionFactory(); + foreignConnectionFactory = createForeignConnectionFactory(); + + outbound = new ActiveMQTopic("RECONNECT.TEST.OUT.TOPIC"); + inbound = new ActiveMQTopic("RECONNECT.TEST.IN.TOPIC"); + + jmsTopicConnector = new SimpleJmsTopicConnector(); + + // Wire the bridges. + jmsTopicConnector.setOutboundTopicBridges( + new OutboundTopicBridge[] {new OutboundTopicBridge("RECONNECT.TEST.OUT.TOPIC")}); + jmsTopicConnector.setInboundTopicBridges( + new InboundTopicBridge[] {new InboundTopicBridge("RECONNECT.TEST.IN.TOPIC")}); + + // Tell it how to reach the two brokers. + jmsTopicConnector.setOutboundTopicConnectionFactory( + new ActiveMQConnectionFactory("tcp://localhost:61617")); + jmsTopicConnector.setLocalTopicConnectionFactory( + new ActiveMQConnectionFactory("tcp://localhost:61616")); + } + + @After + public void tearDown() throws Exception { + disposeConsumerConnections(); + + try { + jmsTopicConnector.stop(); + jmsTopicConnector = null; + } catch (Exception e) { + } + + try { + stopLocalBroker(); + } catch (Throwable e) { + } + try { + stopForeignBroker(); + } catch (Throwable e) { + } + } + + protected void disposeConsumerConnections() { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection connection = iter.next(); + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected void startLocalBroker() throws Exception { + if (localBroker == null) { + localBroker = createFirstBroker(); + localBroker.start(); + localBroker.waitUntilStarted(); + } + } + + protected void stopLocalBroker() throws Exception { + if (localBroker != null) { + localBroker.stop(); + localBroker.waitUntilStopped(); + localBroker = null; + } + } + + protected void startForeignBroker() throws Exception { + if (foreignBroker == null) { + foreignBroker = createSecondBroker(); + foreignBroker.start(); + foreignBroker.waitUntilStarted(); + } + } + + protected void stopForeignBroker() throws Exception { + if (foreignBroker != null) { + foreignBroker.stop(); + foreignBroker.waitUntilStopped(); + foreignBroker = null; + } + } + + protected BrokerService createFirstBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker1"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61616"); + + return broker; + } + + protected BrokerService createSecondBroker() throws Exception { + + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker2"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61617"); + + return broker; + } + + protected ActiveMQConnectionFactory createLocalConnectionFactory() { + return new ActiveMQConnectionFactory("tcp://localhost:61616"); + } + + protected ActiveMQConnectionFactory createForeignConnectionFactory() { + return new ActiveMQConnectionFactory("tcp://localhost:61617"); + } + + protected void sendMessageToForeignBroker(String text) throws JMSException { + Connection connection = null; + try { + connection = localConnectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(outbound); + TextMessage message = session.createTextMessage(); + message.setText(text); + producer.send(message); + } finally { + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected void sendMessageToLocalBroker(String text) throws JMSException { + Connection connection = null; + try { + connection = foreignConnectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(inbound); + TextMessage message = session.createTextMessage(); + message.setText(text); + producer.send(message); + } finally { + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected MessageConsumer createConsumerForLocalBroker() throws JMSException { + Connection connection = localConnectionFactory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session.createConsumer(inbound); + } + + protected MessageConsumer createConsumerForForeignBroker() throws JMSException { + Connection connection = foreignConnectionFactory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session.createConsumer(outbound); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeXBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeXBeanTest.java new file mode 100644 index 0000000000..0b070f2d91 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicBridgeXBeanTest.java @@ -0,0 +1,32 @@ +/** + * 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.network.jms; + +import org.apache.xbean.spring.context.ClassPathXmlApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; + +/** + * + * + */ +public class TopicBridgeXBeanTest extends TopicBridgeSpringTest { + + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/activemq/network/jms/topic-config.xml"); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicOutboundBridgeReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicOutboundBridgeReconnectTest.java new file mode 100644 index 0000000000..6a64b5c187 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/TopicOutboundBridgeReconnectTest.java @@ -0,0 +1,332 @@ +/** + * 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.network.jms; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * These test cases are used to verify that queue outbound bridge connections get + * re-established in all broker restart scenarios. This is possible when the + * outbound bridge is configured using the failover URI with a timeout. + */ +public class TopicOutboundBridgeReconnectTest { + + private BrokerService producerBroker; + private BrokerService consumerBroker; + private ActiveMQConnectionFactory producerConnectionFactory; + private ActiveMQConnectionFactory consumerConnectionFactory; + private Destination destination; + private final ArrayList connections = new ArrayList(); + + @Test + public void testMultipleProducerBrokerRestarts() throws Exception { + for (int i = 0; i < 10; i++) { + testWithProducerBrokerRestart(); + disposeConsumerConnections(); + } + } + + @Test + public void testWithoutRestartsConsumerFirst() throws Exception { + startConsumerBroker(); + startProducerBroker(); + + MessageConsumer consumer = createConsumer(); + + sendMessage("test123"); + sendMessage("test456"); + Message message = consumer.receive(2000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + + message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test456", ((TextMessage)message).getText()); + + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithoutRestartsProducerFirst() throws Exception { + startProducerBroker(); + sendMessage("test123"); + + startConsumerBroker(); + + // unless using a failover URI, the first attempt of this send will likely fail, so increase the timeout below + // to give the bridge time to recover + sendMessage("test456"); + + MessageConsumer consumer = createConsumer(); + Message message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage) message).getText()); + + message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test456", ((TextMessage) message).getText()); + + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithProducerBrokerRestart() throws Exception { + startProducerBroker(); + startConsumerBroker(); + + MessageConsumer consumer = createConsumer(); + + sendMessage("test123"); + Message message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer.receiveNoWait()); + + // Restart the first broker... + stopProducerBroker(); + startProducerBroker(); + + sendMessage("test123"); + message = consumer.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithConsumerBrokerRestart() throws Exception { + startProducerBroker(); + startConsumerBroker(); + + final MessageConsumer consumer1 = createConsumer(); + + sendMessage("test123"); + Message message = consumer1.receive(5000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer1.receiveNoWait()); + consumer1.close(); + + // Restart the first broker... + stopConsumerBroker(); + startConsumerBroker(); + + // unless using a failover URI, the first attempt of this send will likely fail, so increase the timeout below + // to give the bridge time to recover + sendMessage("test123"); + + final MessageConsumer consumer2 = createConsumer(); + assertTrue("Expected recover and delivery failed", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + Message message = consumer2.receiveNoWait(); + if (message == null || !((TextMessage)message).getText().equals("test123")) { + return false; + } + return true; + } + })); + assertNull(consumer2.receiveNoWait()); + } + + @Test + public void testWithConsumerBrokerStartDelay() throws Exception { + startConsumerBroker(); + final MessageConsumer consumer = createConsumer(); + + TimeUnit.SECONDS.sleep(5); + + startProducerBroker(); + + sendMessage("test123"); + assertTrue("Expected recover and delivery failed", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + Message message = consumer.receiveNoWait(); + if (message == null || !((TextMessage)message).getText().equals("test123")) { + return false; + } + return true; + } + })); + assertNull(consumer.receiveNoWait()); + } + + @Test + public void testWithProducerBrokerStartDelay() throws Exception { + startProducerBroker(); + + TimeUnit.SECONDS.sleep(5); + + startConsumerBroker(); + MessageConsumer consumer = createConsumer(); + + sendMessage("test123"); + Message message = consumer.receive(2000); + assertNotNull(message); + assertEquals("test123", ((TextMessage)message).getText()); + assertNull(consumer.receiveNoWait()); + } + + @Before + public void setUp() throws Exception { + producerConnectionFactory = createProducerConnectionFactory(); + consumerConnectionFactory = createConsumerConnectionFactory(); + destination = new ActiveMQTopic("RECONNECT.TEST.TOPIC"); + } + + @After + public void tearDown() throws Exception { + disposeConsumerConnections(); + try { + stopProducerBroker(); + } catch (Throwable e) { + } + try { + stopConsumerBroker(); + } catch (Throwable e) { + } + } + + protected void disposeConsumerConnections() { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + Connection connection = iter.next(); + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected void startProducerBroker() throws Exception { + if (producerBroker == null) { + producerBroker = createFirstBroker(); + producerBroker.start(); + } + } + + protected void stopProducerBroker() throws Exception { + if (producerBroker != null) { + producerBroker.stop(); + producerBroker = null; + } + } + + protected void startConsumerBroker() throws Exception { + if (consumerBroker == null) { + consumerBroker = createSecondBroker(); + consumerBroker.start(); + } + } + + protected void stopConsumerBroker() throws Exception { + if (consumerBroker != null) { + consumerBroker.stop(); + consumerBroker = null; + } + } + + protected BrokerService createFirstBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker1"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61616"); + broker.addConnector("vm://broker1"); + + SimpleJmsTopicConnector jmsTopicConnector = new SimpleJmsTopicConnector(); + jmsTopicConnector.setOutboundTopicBridges( + new OutboundTopicBridge[] {new OutboundTopicBridge("RECONNECT.TEST.TOPIC")}); + jmsTopicConnector.setOutboundTopicConnectionFactory( + new ActiveMQConnectionFactory("tcp://localhost:61617")); + + broker.setJmsBridgeConnectors(new JmsConnector[]{jmsTopicConnector}); + + return broker; + } + + protected BrokerService createSecondBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("broker2"); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:61617"); + broker.addConnector("vm://broker2"); + + return broker; + } + + protected ActiveMQConnectionFactory createProducerConnectionFactory() { + return new ActiveMQConnectionFactory("vm://broker1"); + } + + protected ActiveMQConnectionFactory createConsumerConnectionFactory() { + return new ActiveMQConnectionFactory("vm://broker2"); + } + + protected void sendMessage(String text) throws JMSException { + Connection connection = null; + try { + connection = producerConnectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage(); + message.setText(text); + producer.send(message); + } finally { + try { + connection.close(); + } catch (Throwable ignore) { + } + } + } + + protected MessageConsumer createConsumer() throws JMSException { + Connection connection = consumerConnectionFactory.createConnection(); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session.createConsumer(destination); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/queue-config.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/queue-config.xml new file mode 100644 index 0000000000..a1bc29900e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/queue-config.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + tcp://localhost:61666 + + + + + + + + + + + + + + + + + tcp://localhost:61234 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/queue-xbean.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/queue-xbean.xml new file mode 100644 index 0000000000..017e89c6d0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/queue-xbean.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/topic-config.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/topic-config.xml new file mode 100644 index 0000000000..228274d311 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/topic-config.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + tcp://localhost:61666 + + + + + + + + + + + + + + + + + tcp://localhost:61234 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/topic-spring.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/topic-spring.xml new file mode 100644 index 0000000000..fcb3ec5e2c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/jms/topic-spring.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + tcp://localhost:61666 + + + + + + + + + + + + + + + + + tcp://localhost:61234 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/localBroker-plain.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/localBroker-plain.xml new file mode 100644 index 0000000000..f7db757965 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/localBroker-plain.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/localBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/localBroker.xml new file mode 100644 index 0000000000..5a176a920f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/localBroker.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/multicast/localBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/multicast/localBroker.xml new file mode 100644 index 0000000000..fbdfa06a99 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/multicast/localBroker.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/multicast/remoteBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/multicast/remoteBroker.xml new file mode 100644 index 0000000000..c56e093df5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/multicast/remoteBroker.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/reconnect-broker1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/reconnect-broker1.xml new file mode 100644 index 0000000000..e7c124ea74 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/reconnect-broker1.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/reconnect-broker2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/reconnect-broker2.xml new file mode 100644 index 0000000000..24604d9df5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/reconnect-broker2.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/remoteBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/remoteBroker.xml new file mode 100644 index 0000000000..fadba99168 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/remoteBroker.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ssh-reconnect-broker1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ssh-reconnect-broker1.xml new file mode 100644 index 0000000000..592fd5252b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ssh-reconnect-broker1.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ssh-reconnect-broker2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ssh-reconnect-broker2.xml new file mode 100644 index 0000000000..d3d52ddf12 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/network/ssh-reconnect-broker2.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/BooleanStreamTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/BooleanStreamTest.java new file mode 100644 index 0000000000..ebe1d07e43 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/BooleanStreamTest.java @@ -0,0 +1,149 @@ +/** + * 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.openwire; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +/** + * + */ +public class BooleanStreamTest extends TestCase { + + protected OpenWireFormat openWireformat; + protected int endOfStreamMarker = 0x12345678; + int numberOfBytes = 8 * 200; + + interface BooleanValueSet { + boolean getBooleanValueFor(int index, int count); + } + + public void testBooleanMarshallingUsingAllTrue() throws Exception { + testBooleanStream(numberOfBytes, new BooleanValueSet() { + @Override + public boolean getBooleanValueFor(int index, int count) { + return true; + } + }); + } + + public void testBooleanMarshallingUsingAllFalse() throws Exception { + testBooleanStream(numberOfBytes, new BooleanValueSet() { + @Override + public boolean getBooleanValueFor(int index, int count) { + return false; + } + }); + } + + public void testBooleanMarshallingUsingOddAlternateTrueFalse() throws Exception { + testBooleanStream(numberOfBytes, new BooleanValueSet() { + @Override + public boolean getBooleanValueFor(int index, int count) { + return (index & 1) == 0; + } + }); + } + + public void testBooleanMarshallingUsingEvenAlternateTrueFalse() throws Exception { + testBooleanStream(numberOfBytes, new BooleanValueSet() { + @Override + public boolean getBooleanValueFor(int index, int count) { + return (index & 1) != 0; + } + }); + } + + protected void testBooleanStream(int numberOfBytes, BooleanValueSet valueSet) throws Exception { + for (int i = 0; i < numberOfBytes; i++) { + try { + assertMarshalBooleans(i, valueSet); + } catch (Throwable e) { + throw (AssertionFailedError)new AssertionFailedError("Iteration failed at: " + i).initCause(e); + } + } + } + + protected void assertMarshalBooleans(int count, BooleanValueSet valueSet) throws Exception { + BooleanStream bs = new BooleanStream(); + for (int i = 0; i < count; i++) { + bs.writeBoolean(valueSet.getBooleanValueFor(i, count)); + } + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + DataOutputStream ds = new DataOutputStream(buffer); + bs.marshal(ds); + ds.writeInt(endOfStreamMarker); + + // now lets read from the stream + ds.close(); + + ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray()); + DataInputStream dis = new DataInputStream(in); + bs = new BooleanStream(); + try { + bs.unmarshal(dis); + } catch (Exception e) { + e.printStackTrace(); + fail("Failed to unmarshal: " + count + " booleans: " + e); + } + + for (int i = 0; i < count; i++) { + boolean expected = valueSet.getBooleanValueFor(i, count); + // /System.out.println("Unmarshaling value: " + i + " = " + expected + // + " out of: " + count); + + try { + boolean actual = bs.readBoolean(); + assertEquals("value of object: " + i + " was: " + actual, expected, actual); + } catch (IOException e) { + e.printStackTrace(); + fail("Failed to parse boolean: " + i + " out of: " + count + " due to: " + e); + } + } + int marker = dis.readInt(); + assertEquals("Marker int when unmarshalling: " + count + " booleans", Integer.toHexString(endOfStreamMarker), Integer.toHexString(marker)); + + // lets try read and we should get an exception + try { + dis.readByte(); + fail("Should have reached the end of the stream"); + } catch (IOException e) { + // worked! + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + openWireformat = createOpenWireFormat(); + } + + protected OpenWireFormat createOpenWireFormat() { + OpenWireFormat wf = new OpenWireFormat(); + wf.setCacheEnabled(true); + wf.setStackTraceEnabled(false); + wf.setVersion(1); + return wf; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/BrokerInfoData.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/BrokerInfoData.java new file mode 100644 index 0000000000..baba584907 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/BrokerInfoData.java @@ -0,0 +1,35 @@ +/** + * 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.openwire; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.BrokerInfo; + +public class BrokerInfoData extends DataFileGenerator { + + protected Object createObject() { + BrokerInfo rc = new BrokerInfo(); + rc.setResponseRequired(false); + rc.setBrokerName("localhost"); + rc.setBrokerURL("tcp://localhost:61616"); + rc.setBrokerId(new BrokerId("ID:1289012830123")); + rc.setCommandId((short) 12); + rc.setResponseRequired(false); + return rc; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/DataFileGenerator.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/DataFileGenerator.java new file mode 100644 index 0000000000..ac9311b142 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/DataFileGenerator.java @@ -0,0 +1,141 @@ +/** + * 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.openwire; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + +public abstract class DataFileGenerator extends org.junit.Assert { + + static final File MODULE_BASE_DIR; + static final File CONTROL_DIR; + static final File CLASS_FILE_DIR; + + static { + MODULE_BASE_DIR = new File(System.getProperty("basedir", ".")); + CONTROL_DIR = new File(MODULE_BASE_DIR, "src/test/resources/openwire-control"); + CLASS_FILE_DIR = new File(MODULE_BASE_DIR, "src/test/java/org/apache/activemq/openwire"); + } + + public static void main(String[] args) throws Exception { + generateControlFiles(); + } + + /** + * @param srcdir + * @return + * @throws ClassNotFoundException + * @throws InstantiationException + * @throws IllegalAccessException + */ + public static ArrayList getAllDataFileGenerators() throws Exception { + // System.out.println("Looking for generators in : "+classFileDir); + ArrayList l = new ArrayList(); + File[] files = CLASS_FILE_DIR.listFiles(); + for (int i = 0; files != null && i < files.length; i++) { + File file = files[i]; + if (file.getName().endsWith("Data.java")) { + String cn = file.getName(); + cn = cn.substring(0, cn.length() - ".java".length()); + Class clazz = DataFileGenerator.class.getClassLoader().loadClass("org.apache.activemq.openwire." + cn); + l.add((DataFileGenerator)clazz.newInstance()); + } + } + return l; + } + + private static void generateControlFiles() throws Exception { + ArrayList generators = getAllDataFileGenerators(); + for (DataFileGenerator element : generators) { + try { + // System.out.println("Processing: "+object.getClass()); + element.generateControlFile(); + } catch (Exception e) { + // System.err.println("Error while processing: + // "+object.getClass() + ". Reason: " + e); + } + } + } + + public void generateControlFile() throws Exception { + CONTROL_DIR.mkdirs(); + File dataFile = new File(CONTROL_DIR, getClass().getName() + ".bin"); + + OpenWireFormat wf = new OpenWireFormat(); + wf.setCacheEnabled(false); + wf.setStackTraceEnabled(false); + wf.setVersion(1); + + FileOutputStream os = new FileOutputStream(dataFile); + DataOutputStream ds = new DataOutputStream(os); + wf.marshal(createObject(), ds); + ds.close(); + } + + public InputStream generateInputStream() throws Exception { + OpenWireFormat wf = new OpenWireFormat(); + wf.setCacheEnabled(false); + wf.setStackTraceEnabled(false); + wf.setVersion(1); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + DataOutputStream ds = new DataOutputStream(os); + wf.marshal(createObject(), ds); + ds.close(); + + return new ByteArrayInputStream(os.toByteArray()); + } + + public static void assertAllControlFileAreEqual() throws Exception { + ArrayList generators = getAllDataFileGenerators(); + for (DataFileGenerator element : generators) { + // System.out.println("Processing: "+object.getClass()); + element.assertControlFileIsEqual(); + } + } + + public void assertControlFileIsEqual() throws Exception { + File dataFile = new File(CONTROL_DIR, getClass().getName() + ".bin"); + FileInputStream is1 = new FileInputStream(dataFile); + int pos = 0; + try { + InputStream is2 = generateInputStream(); + int a = is1.read(); + int b = is2.read(); + pos++; + assertEquals("Data does not match control file: " + dataFile + " at byte position " + pos, a, b); + while (a >= 0 && b >= 0) { + a = is1.read(); + b = is2.read(); + pos++; + assertEquals(a, b); + } + is2.close(); + } finally { + is1.close(); + } + } + + protected abstract Object createObject() throws IOException; +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/DataFileGeneratorTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/DataFileGeneratorTestSupport.java new file mode 100644 index 0000000000..b75ba25745 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/DataFileGeneratorTestSupport.java @@ -0,0 +1,330 @@ +/** + * 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.openwire; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.command.DataStructure; +import org.apache.activemq.command.LocalTransactionId; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.command.NetworkBridgeFilter; +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.command.SessionId; +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.filter.BooleanExpression; +import org.apache.activemq.openwire.v1.ActiveMQTextMessageTest; +import org.apache.activemq.openwire.v1.BrokerInfoTest; +import org.apache.activemq.openwire.v1.MessageAckTest; +import org.apache.activemq.test.TestSupport; +import org.apache.activemq.util.ByteSequence; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class DataFileGeneratorTestSupport extends TestSupport { + + protected static final Object[] EMPTY_ARGUMENTS = {}; + private static final Logger LOG = LoggerFactory.getLogger(DataFileGeneratorTestSupport.class); + + private static final Throwable SINGLETON_EXCEPTION = new Exception("shared exception"); + private static final File MODULE_BASE_DIR; + private static final File CONTROL_DIR; + + + static { + File basedir = null; + try { + URL resource = DataFileGeneratorTestSupport.class.getResource("DataFileGeneratorTestSupport.class"); + URI baseURI = new URI(resource.toString()).resolve("../../../../.."); + basedir = new File(baseURI).getCanonicalFile(); + } catch (Exception e) { + throw new RuntimeException(e); + } + MODULE_BASE_DIR = basedir; + CONTROL_DIR = new File(MODULE_BASE_DIR, "src/test/resources/openwire-control"); + } + + private int counter; + private OpenWireFormat openWireformat; + + public void xtestControlFileIsValid() throws Exception { + generateControlFile(); + assertControlFileIsEqual(); + } + + public void testGenerateAndReParsingIsTheSame() throws Exception { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + DataOutputStream ds = new DataOutputStream(buffer); + Object expected = createObject(); + LOG.info("Created: " + expected); + openWireformat.marshal(expected, ds); + ds.close(); + + // now lets try parse it back again + ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray()); + DataInputStream dis = new DataInputStream(in); + Object actual = openWireformat.unmarshal(dis); + assertBeansEqual("", new HashSet(), expected, actual); + + LOG.info("Parsed: " + actual); + } + + protected void assertBeansEqual(String message, Set comparedObjects, Object expected, Object actual) throws Exception { + assertNotNull("Actual object should be equal to: " + expected + " but was null", actual); + if (comparedObjects.contains(expected)) { + return; + } + comparedObjects.add(expected); + Class type = expected.getClass(); + assertEquals("Should be of same type", type, actual.getClass()); + BeanInfo beanInfo = Introspector.getBeanInfo(type); + PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); + for (int i = 0; i < descriptors.length; i++) { + PropertyDescriptor descriptor = descriptors[i]; + Method method = descriptor.getReadMethod(); + if (method != null) { + String name = descriptor.getName(); + Object expectedValue = null; + Object actualValue = null; + try { + expectedValue = method.invoke(expected, EMPTY_ARGUMENTS); + actualValue = method.invoke(actual, EMPTY_ARGUMENTS); + } catch (Exception e) { + LOG.info("Failed to access property: " + name); + } + assertPropertyValuesEqual(message + name, comparedObjects, expectedValue, actualValue); + } + } + } + + protected void assertPropertyValuesEqual(String name, Set comparedObjects, Object expectedValue, Object actualValue) throws Exception { + String message = "Property " + name + " not equal"; + if (expectedValue == null) { + assertNull("Property " + name + " should be null", actualValue); + } else if (expectedValue instanceof Object[]) { + assertArrayEqual(message, comparedObjects, (Object[])expectedValue, (Object[])actualValue); + } else if (expectedValue.getClass().isArray()) { + assertPrimitiveArrayEqual(message, comparedObjects, expectedValue, actualValue); + } else { + if (expectedValue instanceof Exception) { + assertExceptionsEqual(message, (Exception)expectedValue, actualValue); + } else if (expectedValue instanceof ByteSequence) { + assertByteSequencesEqual(message, (ByteSequence)expectedValue, actualValue); + } else if (expectedValue instanceof DataStructure) { + assertBeansEqual(message + name, comparedObjects, expectedValue, actualValue); + } else if (expectedValue instanceof Enumeration) { + assertEnumerationEqual(message + name, comparedObjects, (Enumeration)expectedValue, (Enumeration)actualValue); + } else { + assertEquals(message, expectedValue, actualValue); + } + + } + } + + protected void assertArrayEqual(String message, Set comparedObjects, Object[] expected, Object[] actual) throws Exception { + assertEquals(message + ". Array length", expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertPropertyValuesEqual(message + ". element: " + i, comparedObjects, expected[i], actual[i]); + } + } + + protected void assertEnumerationEqual(String message, Set comparedObjects, Enumeration expected, Enumeration actual) throws Exception { + while (expected.hasMoreElements()) { + Object expectedElem = expected.nextElement(); + Object actualElem = actual.nextElement(); + assertPropertyValuesEqual(message + ". element: " + expectedElem, comparedObjects, expectedElem, actualElem); + } + } + + protected void assertPrimitiveArrayEqual(String message, Set comparedObjects, Object expected, Object actual) throws ArrayIndexOutOfBoundsException, IllegalArgumentException, + Exception { + int length = Array.getLength(expected); + assertEquals(message + ". Array length", length, Array.getLength(actual)); + for (int i = 0; i < length; i++) { + assertPropertyValuesEqual(message + ". element: " + i, comparedObjects, Array.get(expected, i), Array.get(actual, i)); + } + } + + protected void assertByteSequencesEqual(String message, ByteSequence expected, Object actualValue) { + assertTrue(message + ". Actual value should be a ByteSequence but was: " + actualValue, actualValue instanceof ByteSequence); + ByteSequence actual = (ByteSequence)actualValue; + int length = expected.getLength(); + assertEquals(message + ". Length", length, actual.getLength()); + int offset = expected.getOffset(); + assertEquals(message + ". Offset", offset, actual.getOffset()); + byte[] data = expected.getData(); + byte[] actualData = actual.getData(); + for (int i = 0; i < length; i++) { + assertEquals(message + ". Offset " + i, data[offset + i], actualData[offset + i]); + } + } + + protected void assertExceptionsEqual(String message, Exception expected, Object actualValue) { + assertTrue(message + ". Actual value should be an exception but was: " + actualValue, actualValue instanceof Exception); + Exception actual = (Exception)actualValue; + assertEquals(message, expected.getMessage(), actual.getMessage()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + openWireformat = createOpenWireFormat(); + } + + public void generateControlFile() throws Exception { + CONTROL_DIR.mkdirs(); + File dataFile = new File(CONTROL_DIR, getClass().getName() + ".bin"); + + FileOutputStream os = new FileOutputStream(dataFile); + DataOutputStream ds = new DataOutputStream(os); + openWireformat.marshal(createObject(), ds); + ds.close(); + } + + public InputStream generateInputStream() throws Exception { + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + DataOutputStream ds = new DataOutputStream(os); + openWireformat.marshal(createObject(), ds); + ds.close(); + + return new ByteArrayInputStream(os.toByteArray()); + } + + public void assertControlFileIsEqual() throws Exception { + File dataFile = new File(CONTROL_DIR, getClass().getName() + ".bin"); + FileInputStream is1 = new FileInputStream(dataFile); + int pos = 0; + try { + InputStream is2 = generateInputStream(); + int a = is1.read(); + int b = is2.read(); + pos++; + assertEquals("Data does not match control file: " + dataFile + " at byte position " + pos, a, b); + while (a >= 0 && b >= 0) { + a = is1.read(); + b = is2.read(); + pos++; + assertEquals("Data does not match control file: " + dataFile + " at byte position " + pos, a, b); + } + is2.close(); + } finally { + is1.close(); + } + } + + protected abstract Object createObject() throws Exception; + + protected void populateObject(Object info) throws Exception { + // empty method to allow derived classes to call super + // to simplify generated code + } + + protected OpenWireFormat createOpenWireFormat() { + OpenWireFormat wf = new OpenWireFormat(); + wf.setCacheEnabled(true); + wf.setStackTraceEnabled(false); + wf.setVersion(OpenWireFormat.DEFAULT_WIRE_VERSION); + return wf; + } + + protected BrokerId createBrokerId(String text) { + return new BrokerId(text); + } + + protected TransactionId createTransactionId(String string) { + return new LocalTransactionId(createConnectionId(string), ++counter); + } + + protected ConnectionId createConnectionId(String string) { + return new ConnectionId(string); + } + + protected SessionId createSessionId(String string) { + return new SessionId(createConnectionId(string), ++counter); + } + + protected ProducerId createProducerId(String string) { + return new ProducerId(createSessionId(string), ++counter); + } + + protected ConsumerId createConsumerId(String string) { + return new ConsumerId(createSessionId(string), ++counter); + } + + protected MessageId createMessageId(String string) { + return new MessageId(createProducerId(string), ++counter); + } + + protected ActiveMQDestination createActiveMQDestination(String string) { + return new ActiveMQQueue(string); + } + + protected Message createMessage(String string) throws Exception { + ActiveMQTextMessage message = (ActiveMQTextMessage)ActiveMQTextMessageTest.SINGLETON.createObject(); + message.setText(string); + return message; + } + + protected BrokerInfo createBrokerInfo(String string) throws Exception { + return (BrokerInfo)BrokerInfoTest.SINGLETON.createObject(); + } + + protected MessageAck createMessageAck(String string) throws Exception { + return (MessageAck)MessageAckTest.SINGLETON.createObject(); + } + + protected DataStructure createDataStructure(String string) throws Exception { + return createBrokerInfo(string); + } + + protected Throwable createThrowable(String string) { + // we have issues with stack frames not being equal so share the same + // exception each time + return SINGLETON_EXCEPTION; + } + + protected BooleanExpression createBooleanExpression(String string) { + return new NetworkBridgeFilter(null, new BrokerId(string), 10, 10); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/ItStillMarshallsTheSameTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/ItStillMarshallsTheSameTest.java new file mode 100644 index 0000000000..8372f594b9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/ItStillMarshallsTheSameTest.java @@ -0,0 +1,27 @@ +/** + * 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.openwire; + +import junit.framework.TestCase; + +public class ItStillMarshallsTheSameTest extends TestCase { + + public void testAll() throws Exception { + BrokerInfoData.assertAllControlFileAreEqual(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/NumberRangesWhileMarshallingTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/NumberRangesWhileMarshallingTest.java new file mode 100644 index 0000000000..973a00734b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/NumberRangesWhileMarshallingTest.java @@ -0,0 +1,145 @@ +/** + * 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.openwire; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.SessionId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class NumberRangesWhileMarshallingTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(NumberRangesWhileMarshallingTest.class); + + protected String connectionId = "Cheese"; + protected ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + protected DataOutputStream ds = new DataOutputStream(buffer); + protected OpenWireFormat openWireformat; + protected int endOfStreamMarker = 0x12345678; + + public void testLongNumberRanges() throws Exception { + long[] numberValues = { + // bytes + 0, 1, 0x7e, 0x7f, 0x80, 0x81, 0xf0, 0xff, + // shorts + 0x7eff, 0x7fffL, 0x8001L, 0x8000L, 0xe000L, 0xe0001L, 0xff00L, 0xffffL, + // ints + 0x10000L, 0x700000L, 0x12345678L, 0x72345678L, 0x7fffffffL, 0x80000000L, 0x80000001L, 0xE0000001L, 0xFFFFFFFFL, + // 3 byte longs + 0x123456781L, 0x1234567812L, 0x12345678123L, 0x123456781234L, 0x1234567812345L, 0x12345678123456L, 0x7e345678123456L, 0x7fffffffffffffL, + 0x80000000000000L, 0x80000000000001L, 0xe0000000000001L, 0xffffffffffffffL, + // 4 byte longs + 0x1234567812345678L, 0x7fffffffffffffffL, 0x8000000000000000L, 0x8000000000000001L, 0xe000000000000001L, 0xffffffffffffffffL, 1 + }; + + for (int i = 0; i < numberValues.length; i++) { + long value = numberValues[i]; + + SessionId object = new SessionId(); + object.setConnectionId(connectionId); + object.setValue(value); + writeObject(object); + } + ds.writeInt(endOfStreamMarker); + + // now lets read from the stream + ds.close(); + + ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray()); + DataInputStream dis = new DataInputStream(in); + for (int i = 0; i < numberValues.length; i++) { + long value = numberValues[i]; + String expected = Long.toHexString(value); + LOG.info("Unmarshaling value: " + i + " = " + expected); + + SessionId command = (SessionId)openWireformat.unmarshal(dis); + assertEquals("connection ID in object: " + i, connectionId, command.getConnectionId()); + String actual = Long.toHexString(command.getValue()); + assertEquals("value of object: " + i + " was: " + actual, expected, actual); + } + int marker = dis.readInt(); + assertEquals("Marker int", Integer.toHexString(endOfStreamMarker), Integer.toHexString(marker)); + + // lets try read and we should get an exception + try { + byte value = dis.readByte(); + fail("Should have reached the end of the stream: " + value); + } catch (IOException e) { + // worked! + } + } + + public void testMaxFrameSize() throws Exception { + OpenWireFormat wf = new OpenWireFormat(); + wf.setMaxFrameSize(10); + ActiveMQTextMessage msg = new ActiveMQTextMessage(); + msg.setText("This is a test"); + + writeObject(msg); + ds.writeInt(endOfStreamMarker); + + // now lets read from the stream + ds.close(); + + ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray()); + DataInputStream dis = new DataInputStream(in); + + try { + wf.unmarshal(dis); + } catch (IOException ioe) { + return; + } + + fail("Should fail because of the large frame size"); + + + } + + public void testDefaultMaxFrameSizeUnlimited() { + OpenWireFormat wf = new OpenWireFormat(); + assertEquals(Long.MAX_VALUE, wf.getMaxFrameSize()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + openWireformat = createOpenWireFormat(); + } + + protected OpenWireFormat createOpenWireFormat() { + OpenWireFormat wf = new OpenWireFormat(); + wf.setCacheEnabled(true); + wf.setStackTraceEnabled(false); + wf.setVersion(1); + return wf; + } + + private void writeObject(Object object) throws IOException { + openWireformat.marshal(object, ds); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/WireFormatInfoData.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/WireFormatInfoData.java new file mode 100644 index 0000000000..208a6ed2d1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/WireFormatInfoData.java @@ -0,0 +1,33 @@ +/** + * 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.openwire; + +import java.io.IOException; + +import org.apache.activemq.command.WireFormatInfo; + +public class WireFormatInfoData extends DataFileGenerator { + + protected Object createObject() throws IOException { + WireFormatInfo rc = new WireFormatInfo(); + rc.setResponseRequired(false); + rc.setCacheEnabled(true); + rc.setVersion(1); + return rc; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQBytesMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQBytesMessageTest.java new file mode 100644 index 0000000000..a6a649c1c7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQBytesMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQBytesMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQBytesMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQBytesMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQBytesMessageTest SINGLETON = new ActiveMQBytesMessageTest(); + + public Object createObject() throws Exception { + ActiveMQBytesMessage info = new ActiveMQBytesMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQBytesMessage info = (ActiveMQBytesMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQDestinationTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQDestinationTestSupport.java new file mode 100644 index 0000000000..bfa4aedfe8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQDestinationTestSupport.java @@ -0,0 +1,40 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for ActiveMQDestination + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public abstract class ActiveMQDestinationTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQDestination info = (ActiveMQDestination)object; + info.setPhysicalName("PhysicalName:1"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQMapMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQMapMessageTest.java new file mode 100644 index 0000000000..2a0915478b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQMapMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQMapMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQMapMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQMapMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQMapMessageTest SINGLETON = new ActiveMQMapMessageTest(); + + public Object createObject() throws Exception { + ActiveMQMapMessage info = new ActiveMQMapMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQMapMessage info = (ActiveMQMapMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQMessageTest.java new file mode 100644 index 0000000000..79f252056d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQMessageTest extends MessageTestSupport { + + public static final ActiveMQMessageTest SINGLETON = new ActiveMQMessageTest(); + + public Object createObject() throws Exception { + ActiveMQMessage info = new ActiveMQMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQMessage info = (ActiveMQMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQObjectMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQObjectMessageTest.java new file mode 100644 index 0000000000..30d1476505 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQObjectMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQObjectMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQObjectMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQObjectMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQObjectMessageTest SINGLETON = new ActiveMQObjectMessageTest(); + + public Object createObject() throws Exception { + ActiveMQObjectMessage info = new ActiveMQObjectMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQObjectMessage info = (ActiveMQObjectMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQQueueTest.java new file mode 100644 index 0000000000..459090c5e4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQQueueTest.java @@ -0,0 +1,44 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQQueue; + +/** + * Test case for the OpenWire marshalling for ActiveMQQueue NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQQueueTest extends ActiveMQDestinationTestSupport { + + public static final ActiveMQQueueTest SINGLETON = new ActiveMQQueueTest(); + + public Object createObject() throws Exception { + ActiveMQQueue info = new ActiveMQQueue(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQQueue info = (ActiveMQQueue)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQStreamMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQStreamMessageTest.java new file mode 100644 index 0000000000..6648554646 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQStreamMessageTest.java @@ -0,0 +1,44 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQStreamMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQStreamMessage NOTE!: This + * file is auto generated - do not modify! if you need to make a change, please + * see the modify the groovy scripts in the under src/gram/script and then use + * maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQStreamMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQStreamMessageTest SINGLETON = new ActiveMQStreamMessageTest(); + + public Object createObject() throws Exception { + ActiveMQStreamMessage info = new ActiveMQStreamMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQStreamMessage info = (ActiveMQStreamMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempDestinationTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempDestinationTestSupport.java new file mode 100644 index 0000000000..73133c470a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempDestinationTestSupport.java @@ -0,0 +1,36 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQTempDestination; + +/** + * Test case for the OpenWire marshalling for ActiveMQTempDestination NOTE!: + * This file is auto generated - do not modify! if you need to make a change, + * please see the modify the groovy scripts in the under src/gram/script and + * then use maven openwire:generate to regenerate this file. + * + * + */ +public abstract class ActiveMQTempDestinationTestSupport extends ActiveMQDestinationTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTempDestination info = (ActiveMQTempDestination)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempQueueTest.java new file mode 100644 index 0000000000..c358a5a808 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempQueueTest.java @@ -0,0 +1,44 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQTempQueue; + +/** + * Test case for the OpenWire marshalling for ActiveMQTempQueue NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTempQueueTest extends ActiveMQTempDestinationTestSupport { + + public static final ActiveMQTempQueueTest SINGLETON = new ActiveMQTempQueueTest(); + + public Object createObject() throws Exception { + ActiveMQTempQueue info = new ActiveMQTempQueue(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTempQueue info = (ActiveMQTempQueue)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempTopicTest.java new file mode 100644 index 0000000000..18e33c0e34 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTempTopicTest.java @@ -0,0 +1,44 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQTempTopic; + +/** + * Test case for the OpenWire marshalling for ActiveMQTempTopic NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTempTopicTest extends ActiveMQTempDestinationTestSupport { + + public static final ActiveMQTempTopicTest SINGLETON = new ActiveMQTempTopicTest(); + + public Object createObject() throws Exception { + ActiveMQTempTopic info = new ActiveMQTempTopic(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTempTopic info = (ActiveMQTempTopic)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTextMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTextMessageTest.java new file mode 100644 index 0000000000..839d713673 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTextMessageTest.java @@ -0,0 +1,44 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQTextMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQTextMessage NOTE!: This + * file is auto generated - do not modify! if you need to make a change, please + * see the modify the groovy scripts in the under src/gram/script and then use + * maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTextMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQTextMessageTest SINGLETON = new ActiveMQTextMessageTest(); + + public Object createObject() throws Exception { + ActiveMQTextMessage info = new ActiveMQTextMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTextMessage info = (ActiveMQTextMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTopicTest.java new file mode 100644 index 0000000000..a08d43ae79 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ActiveMQTopicTest.java @@ -0,0 +1,44 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ActiveMQTopic; + +/** + * Test case for the OpenWire marshalling for ActiveMQTopic NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTopicTest extends ActiveMQDestinationTestSupport { + + public static final ActiveMQTopicTest SINGLETON = new ActiveMQTopicTest(); + + public Object createObject() throws Exception { + ActiveMQTopic info = new ActiveMQTopic(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTopic info = (ActiveMQTopic)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BaseCommandTestSupport.java new file mode 100644 index 0000000000..3240cf0a17 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BaseCommandTestSupport.java @@ -0,0 +1,39 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BrokerIdTest.java new file mode 100644 index 0000000000..1893de3100 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BrokerIdTest.java @@ -0,0 +1,48 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BrokerId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class BrokerIdTest extends DataFileGeneratorTestSupport { + + public static final BrokerIdTest SINGLETON = new BrokerIdTest(); + + public Object createObject() throws Exception { + BrokerId info = new BrokerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerId info = (BrokerId)object; + info.setValue("Value:1"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BrokerInfoTest.java new file mode 100644 index 0000000000..e0541e2ab8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/BrokerInfoTest.java @@ -0,0 +1,58 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.BrokerInfo; + +/** + * Test case for the OpenWire marshalling for BrokerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class BrokerInfoTest extends BaseCommandTestSupport { + + public static final BrokerInfoTest SINGLETON = new BrokerInfoTest(); + + public Object createObject() throws Exception { + BrokerInfo info = new BrokerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerInfo info = (BrokerInfo)object; + info.setBrokerId(createBrokerId("BrokerId:1")); + info.setBrokerURL("BrokerURL:2"); + + { + BrokerInfo value[] = new BrokerInfo[0]; + for (int i = 0; i < 0; i++) { + value[i] = createBrokerInfo("PeerBrokerInfos:3"); + } + info.setPeerBrokerInfos(value); + } + info.setBrokerName("BrokerName:4"); + info.setSlaveBroker(true); + info.setMasterBroker(false); + info.setFaultTolerantConfiguration(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionControlTest.java new file mode 100644 index 0000000000..4dae00326d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionControlTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ConnectionControl; + +/** + * Test case for the OpenWire marshalling for ConnectionControl + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ConnectionControlTest extends BaseCommandTestSupport { + + public static final ConnectionControlTest SINGLETON = new ConnectionControlTest(); + + public Object createObject() throws Exception { + ConnectionControl info = new ConnectionControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionControl info = (ConnectionControl)object; + info.setClose(true); + info.setExit(false); + info.setFaultTolerant(true); + info.setResume(false); + info.setSuspend(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionErrorTest.java new file mode 100644 index 0000000000..438fe6b373 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionErrorTest.java @@ -0,0 +1,48 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ConnectionError; + +/** + * Test case for the OpenWire marshalling for ConnectionError + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ConnectionErrorTest extends BaseCommandTestSupport { + + public static final ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); + + public Object createObject() throws Exception { + ConnectionError info = new ConnectionError(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionError info = (ConnectionError)object; + info.setException(createThrowable("Exception:1")); + info.setConnectionId(createConnectionId("ConnectionId:2")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionIdTest.java new file mode 100644 index 0000000000..3dd221e28c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionIdTest.java @@ -0,0 +1,48 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for ConnectionId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ConnectionIdTest extends DataFileGeneratorTestSupport { + + public static final ConnectionIdTest SINGLETON = new ConnectionIdTest(); + + public Object createObject() throws Exception { + ConnectionId info = new ConnectionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionId info = (ConnectionId)object; + info.setValue("Value:1"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionInfoTest.java new file mode 100644 index 0000000000..9b457272b3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConnectionInfoTest.java @@ -0,0 +1,59 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ConnectionInfo; + +/** + * Test case for the OpenWire marshalling for ConnectionInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ConnectionInfoTest extends BaseCommandTestSupport { + + public static final ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); + + public Object createObject() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionInfo info = (ConnectionInfo)object; + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setClientId("ClientId:2"); + info.setPassword("Password:3"); + info.setUserName("UserName:4"); + + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setBrokerMasterConnector(true); + info.setManageable(false); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerControlTest.java new file mode 100644 index 0000000000..4ea061d01a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerControlTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ConsumerControl; + +/** + * Test case for the OpenWire marshalling for ConsumerControl + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ConsumerControlTest extends BaseCommandTestSupport { + + public static final ConsumerControlTest SINGLETON = new ConsumerControlTest(); + + public Object createObject() throws Exception { + ConsumerControl info = new ConsumerControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerControl info = (ConsumerControl)object; + info.setClose(true); + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setPrefetch(1); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerIdTest.java new file mode 100644 index 0000000000..c31d8ef350 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerIdTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for ConsumerId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ConsumerIdTest extends DataFileGeneratorTestSupport { + + public static final ConsumerIdTest SINGLETON = new ConsumerIdTest(); + + public Object createObject() throws Exception { + ConsumerId info = new ConsumerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerId info = (ConsumerId)object; + info.setConnectionId("ConnectionId:1"); + info.setSessionId(1); + info.setValue(2); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerInfoTest.java new file mode 100644 index 0000000000..50efd51e0d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ConsumerInfoTest.java @@ -0,0 +1,69 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ConsumerInfo; + +/** + * Test case for the OpenWire marshalling for ConsumerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ConsumerInfoTest extends BaseCommandTestSupport { + + public static final ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); + + public Object createObject() throws Exception { + ConsumerInfo info = new ConsumerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerInfo info = (ConsumerInfo)object; + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setBrowser(true); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setPrefetchSize(1); + info.setMaximumPendingMessageLimit(2); + info.setDispatchAsync(false); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubcriptionName:4"); + info.setNoLocal(true); + info.setExclusive(false); + info.setRetroactive(true); + info.setPriority((byte)1); + + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); + info.setNetworkSubscription(false); + info.setOptimizedAcknowledge(true); + info.setNoRangeAcks(false); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ControlCommandTest.java new file mode 100644 index 0000000000..1efa08d158 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ControlCommandTest.java @@ -0,0 +1,47 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ControlCommand; + +/** + * Test case for the OpenWire marshalling for ControlCommand + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ControlCommandTest extends BaseCommandTestSupport { + + public static final ControlCommandTest SINGLETON = new ControlCommandTest(); + + public Object createObject() throws Exception { + ControlCommand info = new ControlCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ControlCommand info = (ControlCommand)object; + info.setCommand("Command:1"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DataArrayResponseTest.java new file mode 100644 index 0000000000..3523ea74f2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DataArrayResponseTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.DataArrayResponse; +import org.apache.activemq.command.DataStructure; + +/** + * Test case for the OpenWire marshalling for DataArrayResponse NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class DataArrayResponseTest extends ResponseTest { + + public static final DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); + + public Object createObject() throws Exception { + DataArrayResponse info = new DataArrayResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataArrayResponse info = (DataArrayResponse)object; + + { + DataStructure value[] = new DataStructure[2]; + for (int i = 0; i < 2; i++) { + value[i] = createDataStructure("Data:1"); + } + info.setData(value); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DataResponseTest.java new file mode 100644 index 0000000000..cffbd0a223 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DataResponseTest.java @@ -0,0 +1,47 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.DataResponse; + +/** + * Test case for the OpenWire marshalling for DataResponse + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class DataResponseTest extends ResponseTest { + + public static final DataResponseTest SINGLETON = new DataResponseTest(); + + public Object createObject() throws Exception { + DataResponse info = new DataResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataResponse info = (DataResponse)object; + info.setData(createDataStructure("Data:1")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DestinationInfoTest.java new file mode 100644 index 0000000000..20688f5ea7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DestinationInfoTest.java @@ -0,0 +1,57 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.DestinationInfo; + +/** + * Test case for the OpenWire marshalling for DestinationInfo NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class DestinationInfoTest extends BaseCommandTestSupport { + + public static final DestinationInfoTest SINGLETON = new DestinationInfoTest(); + + public Object createObject() throws Exception { + DestinationInfo info = new DestinationInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DestinationInfo info = (DestinationInfo)object; + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setOperationType((byte)1); + info.setTimeout(1); + + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DiscoveryEventTest.java new file mode 100644 index 0000000000..33a33b59ea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/DiscoveryEventTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.DiscoveryEvent; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for DiscoveryEvent + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class DiscoveryEventTest extends DataFileGeneratorTestSupport { + + public static final DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); + + public Object createObject() throws Exception { + DiscoveryEvent info = new DiscoveryEvent(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DiscoveryEvent info = (DiscoveryEvent)object; + info.setServiceName("ServiceName:1"); + info.setBrokerName("BrokerName:2"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ExceptionResponseTest.java new file mode 100644 index 0000000000..01074ecd0d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ExceptionResponseTest.java @@ -0,0 +1,47 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ExceptionResponse; + +/** + * Test case for the OpenWire marshalling for ExceptionResponse + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ExceptionResponseTest extends ResponseTest { + + public static final ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); + + public Object createObject() throws Exception { + ExceptionResponse info = new ExceptionResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ExceptionResponse info = (ExceptionResponse)object; + info.setException(createThrowable("Exception:1")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/FlushCommandTest.java new file mode 100644 index 0000000000..508444016c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/FlushCommandTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.FlushCommand; + +/** + * Test case for the OpenWire marshalling for FlushCommand + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class FlushCommandTest extends BaseCommandTestSupport { + + public static final FlushCommandTest SINGLETON = new FlushCommandTest(); + + public Object createObject() throws Exception { + FlushCommand info = new FlushCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + FlushCommand info = (FlushCommand)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/IntegerResponseTest.java new file mode 100644 index 0000000000..fb33c720e4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/IntegerResponseTest.java @@ -0,0 +1,47 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.IntegerResponse; + +/** + * Test case for the OpenWire marshalling for IntegerResponse + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class IntegerResponseTest extends ResponseTest { + + public static final IntegerResponseTest SINGLETON = new IntegerResponseTest(); + + public Object createObject() throws Exception { + IntegerResponse info = new IntegerResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + IntegerResponse info = (IntegerResponse)object; + info.setResult(1); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalQueueAckTest.java new file mode 100644 index 0000000000..47ace83e45 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalQueueAckTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.JournalQueueAck; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for JournalQueueAck + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class JournalQueueAckTest extends DataFileGeneratorTestSupport { + + public static final JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); + + public Object createObject() throws Exception { + JournalQueueAck info = new JournalQueueAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalQueueAck info = (JournalQueueAck)object; + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageAck(createMessageAck("MessageAck:2")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTopicAckTest.java new file mode 100644 index 0000000000..d74528b1ea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTopicAckTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.JournalTopicAck; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for JournalTopicAck + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class JournalTopicAckTest extends DataFileGeneratorTestSupport { + + public static final JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); + + public Object createObject() throws Exception { + JournalTopicAck info = new JournalTopicAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTopicAck info = (JournalTopicAck)object; + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageId(createMessageId("MessageId:2")); + info.setMessageSequenceId(1); + info.setSubscritionName("SubscritionName:3"); + info.setClientId("ClientId:4"); + info.setTransactionId(createTransactionId("TransactionId:5")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTraceTest.java new file mode 100644 index 0000000000..aad70601ff --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTraceTest.java @@ -0,0 +1,48 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.JournalTrace; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for JournalTrace + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class JournalTraceTest extends DataFileGeneratorTestSupport { + + public static final JournalTraceTest SINGLETON = new JournalTraceTest(); + + public Object createObject() throws Exception { + JournalTrace info = new JournalTrace(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTrace info = (JournalTrace)object; + info.setMessage("Message:1"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTransactionTest.java new file mode 100644 index 0000000000..6e7008e96b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/JournalTransactionTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.JournalTransaction; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for JournalTransaction + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class JournalTransactionTest extends DataFileGeneratorTestSupport { + + public static final JournalTransactionTest SINGLETON = new JournalTransactionTest(); + + public Object createObject() throws Exception { + JournalTransaction info = new JournalTransaction(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTransaction info = (JournalTransaction)object; + info.setTransactionId(createTransactionId("TransactionId:1")); + info.setType((byte)1); + info.setWasPrepared(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/KeepAliveInfoTest.java new file mode 100644 index 0000000000..4a880bf2d8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/KeepAliveInfoTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.KeepAliveInfo; + +/** + * Test case for the OpenWire marshalling for KeepAliveInfo + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class KeepAliveInfoTest extends BaseCommandTestSupport { + + public static final KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); + + public Object createObject() throws Exception { + KeepAliveInfo info = new KeepAliveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + KeepAliveInfo info = (KeepAliveInfo)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/LastPartialCommandTest.java new file mode 100644 index 0000000000..c992ad4b54 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/LastPartialCommandTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.LastPartialCommand; + +/** + * Test case for the OpenWire marshalling for LastPartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class LastPartialCommandTest extends PartialCommandTest { + + public static final LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); + + public Object createObject() throws Exception { + LastPartialCommand info = new LastPartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LastPartialCommand info = (LastPartialCommand)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/LocalTransactionIdTest.java new file mode 100644 index 0000000000..2275a30e2e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/LocalTransactionIdTest.java @@ -0,0 +1,48 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.LocalTransactionId; + +/** + * Test case for the OpenWire marshalling for LocalTransactionId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class LocalTransactionIdTest extends TransactionIdTestSupport { + + public static final LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); + + public Object createObject() throws Exception { + LocalTransactionId info = new LocalTransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LocalTransactionId info = (LocalTransactionId)object; + info.setValue(1); + info.setConnectionId(createConnectionId("ConnectionId:1")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageAckTest.java new file mode 100644 index 0000000000..1a055dad37 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageAckTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.MessageAck; + +/** + * Test case for the OpenWire marshalling for MessageAck + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class MessageAckTest extends BaseCommandTestSupport { + + public static final MessageAckTest SINGLETON = new MessageAckTest(); + + public Object createObject() throws Exception { + MessageAck info = new MessageAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageAck info = (MessageAck)object; + info.setDestination(createActiveMQDestination("Destination:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setConsumerId(createConsumerId("ConsumerId:3")); + info.setAckType((byte)1); + info.setFirstMessageId(createMessageId("FirstMessageId:4")); + info.setLastMessageId(createMessageId("LastMessageId:5")); + info.setMessageCount(1); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..94589e554c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageDispatchNotificationTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.MessageDispatchNotification; + +/** + * Test case for the OpenWire marshalling for MessageDispatchNotification + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class MessageDispatchNotificationTest extends BaseCommandTestSupport { + + public static final MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); + + public Object createObject() throws Exception { + MessageDispatchNotification info = new MessageDispatchNotification(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatchNotification info = (MessageDispatchNotification)object; + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setDeliverySequenceId(1); + info.setMessageId(createMessageId("MessageId:3")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageDispatchTest.java new file mode 100644 index 0000000000..f7ffda674a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageDispatchTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.MessageDispatch; + +/** + * Test case for the OpenWire marshalling for MessageDispatch + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class MessageDispatchTest extends BaseCommandTestSupport { + + public static final MessageDispatchTest SINGLETON = new MessageDispatchTest(); + + public Object createObject() throws Exception { + MessageDispatch info = new MessageDispatch(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatch info = (MessageDispatch)object; + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setMessage(createMessage("Message:3")); + info.setRedeliveryCounter(1); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageIdTest.java new file mode 100644 index 0000000000..4f3b4f6816 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageIdTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.MessageId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for MessageId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class MessageIdTest extends DataFileGeneratorTestSupport { + + public static final MessageIdTest SINGLETON = new MessageIdTest(); + + public Object createObject() throws Exception { + MessageId info = new MessageId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageId info = (MessageId)object; + info.setProducerId(createProducerId("ProducerId:1")); + info.setProducerSequenceId(1); + info.setBrokerSequenceId(2); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageTestSupport.java new file mode 100644 index 0000000000..037375cbb4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/MessageTestSupport.java @@ -0,0 +1,92 @@ +/** + * 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.openwire.v1; + +import java.io.DataOutputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.Message; +import org.apache.activemq.util.ByteArrayOutputStream; +import org.apache.activemq.util.MarshallingSupport; + +/** + * Test case for the OpenWire marshalling for Message NOTE!: This file is auto + * generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public abstract class MessageTestSupport extends BaseCommandTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Message info = (Message)object; + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTransactionId(createTransactionId("TransactionId:3")); + info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); + info.setMessageId(createMessageId("MessageId:5")); + info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); + info.setGroupID("GroupID:7"); + info.setGroupSequence(1); + info.setCorrelationId("CorrelationId:8"); + info.setPersistent(true); + info.setExpiration(1); + info.setPriority((byte)1); + info.setReplyTo(createActiveMQDestination("ReplyTo:9")); + info.setTimestamp(2); + info.setType("Type:10"); + + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(baos); + MarshallingSupport.writeUTF8(dataOut, "Content:11"); + dataOut.close(); + info.setContent(baos.toByteSequence()); + } + + { + Map map = new HashMap(); + map.put("MarshalledProperties", 12); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + MarshallingSupport.marshalPrimitiveMap(map, os); + os.close(); + info.setMarshalledProperties(baos.toByteSequence()); + } + + info.setDataStructure(createDataStructure("DataStructure:13")); + info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); + info.setCompressed(false); + info.setRedeliveryCounter(2); + + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:15"); + } + info.setBrokerPath(value); + } + info.setArrival(3); + info.setUserID("UserID:16"); + info.setRecievedByDFBridge(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..068af0b2ef --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/NetworkBridgeFilterTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.NetworkBridgeFilter; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for NetworkBridgeFilter + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { + + public static final NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); + + public Object createObject() throws Exception { + NetworkBridgeFilter info = new NetworkBridgeFilter(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + NetworkBridgeFilter info = (NetworkBridgeFilter)object; + info.setNetworkTTL(1); + info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/PartialCommandTest.java new file mode 100644 index 0000000000..bdbe27d2a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/PartialCommandTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.PartialCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for PartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class PartialCommandTest extends DataFileGeneratorTestSupport { + + public static final PartialCommandTest SINGLETON = new PartialCommandTest(); + + public Object createObject() throws Exception { + PartialCommand info = new PartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + PartialCommand info = (PartialCommand)object; + info.setCommandId(1); + info.setData("Data:1".getBytes()); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ProducerIdTest.java new file mode 100644 index 0000000000..d67dbaf375 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ProducerIdTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for ProducerId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ProducerIdTest extends DataFileGeneratorTestSupport { + + public static final ProducerIdTest SINGLETON = new ProducerIdTest(); + + public Object createObject() throws Exception { + ProducerId info = new ProducerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerId info = (ProducerId)object; + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + info.setSessionId(2); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ProducerInfoTest.java new file mode 100644 index 0000000000..8d8b5b8159 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ProducerInfoTest.java @@ -0,0 +1,55 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ProducerInfo; + +/** + * Test case for the OpenWire marshalling for ProducerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ProducerInfoTest extends BaseCommandTestSupport { + + public static final ProducerInfoTest SINGLETON = new ProducerInfoTest(); + + public Object createObject() throws Exception { + ProducerInfo info = new ProducerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerInfo info = (ProducerInfo)object; + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/RemoveInfoTest.java new file mode 100644 index 0000000000..3d09942ed2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/RemoveInfoTest.java @@ -0,0 +1,47 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.RemoveInfo; + +/** + * Test case for the OpenWire marshalling for RemoveInfo + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class RemoveInfoTest extends BaseCommandTestSupport { + + public static final RemoveInfoTest SINGLETON = new RemoveInfoTest(); + + public Object createObject() throws Exception { + RemoveInfo info = new RemoveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveInfo info = (RemoveInfo)object; + info.setObjectId(createDataStructure("ObjectId:1")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..32697dda92 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/RemoveSubscriptionInfoTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.RemoveSubscriptionInfo; + +/** + * Test case for the OpenWire marshalling for RemoveSubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { + + public static final RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); + + public Object createObject() throws Exception { + RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveSubscriptionInfo info = (RemoveSubscriptionInfo)object; + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setSubscriptionName("SubcriptionName:2"); + info.setClientId("ClientId:3"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ReplayCommandTest.java new file mode 100644 index 0000000000..d9decb4641 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ReplayCommandTest.java @@ -0,0 +1,48 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ReplayCommand; + +/** + * Test case for the OpenWire marshalling for ReplayCommand + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ReplayCommandTest extends BaseCommandTestSupport { + + public static final ReplayCommandTest SINGLETON = new ReplayCommandTest(); + + public Object createObject() throws Exception { + ReplayCommand info = new ReplayCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ReplayCommand info = (ReplayCommand)object; + info.setFirstNakNumber(1); + info.setLastNakNumber(2); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ResponseTest.java new file mode 100644 index 0000000000..80c6fa4f5f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ResponseTest.java @@ -0,0 +1,47 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.Response; + +/** + * Test case for the OpenWire marshalling for Response + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ResponseTest extends BaseCommandTestSupport { + + public static final ResponseTest SINGLETON = new ResponseTest(); + + public Object createObject() throws Exception { + Response info = new Response(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Response info = (Response)object; + info.setCorrelationId(1); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SessionIdTest.java new file mode 100644 index 0000000000..a928a4b09b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SessionIdTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.SessionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for SessionId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class SessionIdTest extends DataFileGeneratorTestSupport { + + public static final SessionIdTest SINGLETON = new SessionIdTest(); + + public Object createObject() throws Exception { + SessionId info = new SessionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionId info = (SessionId)object; + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SessionInfoTest.java new file mode 100644 index 0000000000..8dc1bb0cbe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SessionInfoTest.java @@ -0,0 +1,47 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.SessionInfo; + +/** + * Test case for the OpenWire marshalling for SessionInfo + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class SessionInfoTest extends BaseCommandTestSupport { + + public static final SessionInfoTest SINGLETON = new SessionInfoTest(); + + public Object createObject() throws Exception { + SessionInfo info = new SessionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionInfo info = (SessionInfo)object; + info.setSessionId(createSessionId("SessionId:1")); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ShutdownInfoTest.java new file mode 100644 index 0000000000..ee8dc4da38 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/ShutdownInfoTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.ShutdownInfo; + +/** + * Test case for the OpenWire marshalling for ShutdownInfo + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ShutdownInfoTest extends BaseCommandTestSupport { + + public static final ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); + + public Object createObject() throws Exception { + ShutdownInfo info = new ShutdownInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ShutdownInfo info = (ShutdownInfo)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SubscriptionInfoTest.java new file mode 100644 index 0000000000..5eae49607a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/SubscriptionInfoTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.SubscriptionInfo; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for SubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { + + public static final SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); + + public Object createObject() throws Exception { + SubscriptionInfo info = new SubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SubscriptionInfo info = (SubscriptionInfo)object; + info.setClientId("ClientId:1"); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubcriptionName:4"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/TransactionIdTestSupport.java new file mode 100644 index 0000000000..8c77aa938f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/TransactionIdTestSupport.java @@ -0,0 +1,39 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for TransactionId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionId info = (TransactionId)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/TransactionInfoTest.java new file mode 100644 index 0000000000..a5e558b8fd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/TransactionInfoTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.TransactionInfo; + +/** + * Test case for the OpenWire marshalling for TransactionInfo + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class TransactionInfoTest extends BaseCommandTestSupport { + + public static final TransactionInfoTest SINGLETON = new TransactionInfoTest(); + + public Object createObject() throws Exception { + TransactionInfo info = new TransactionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionInfo info = (TransactionInfo)object; + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setType((byte)1); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/WireFormatInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/WireFormatInfoTest.java new file mode 100644 index 0000000000..5298b99663 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/WireFormatInfoTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.WireFormatInfo; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for WireFormatInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class WireFormatInfoTest extends DataFileGeneratorTestSupport { + + public static final WireFormatInfoTest SINGLETON = new WireFormatInfoTest(); + + public Object createObject() throws Exception { + WireFormatInfo info = new WireFormatInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + WireFormatInfo info = (WireFormatInfo)object; + info.setVersion(1); + + { + byte data[] = "MarshalledProperties:1".getBytes(); + info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data, 0, data.length)); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/XATransactionIdTest.java new file mode 100644 index 0000000000..013c9864a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v1/XATransactionIdTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v1; + +import org.apache.activemq.command.XATransactionId; + +/** + * Test case for the OpenWire marshalling for XATransactionId + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class XATransactionIdTest extends TransactionIdTestSupport { + + public static final XATransactionIdTest SINGLETON = new XATransactionIdTest(); + + public Object createObject() throws Exception { + XATransactionId info = new XATransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + XATransactionId info = (XATransactionId)object; + info.setFormatId(1); + info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); + info.setBranchQualifier("BranchQualifier:2".getBytes()); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQBytesMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQBytesMessageTest.java new file mode 100644 index 0000000000..458821964c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQBytesMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQBytesMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQBytesMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQBytesMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQBytesMessageTest SINGLETON = new ActiveMQBytesMessageTest(); + + public Object createObject() throws Exception { + ActiveMQBytesMessage info = new ActiveMQBytesMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQBytesMessage info = (ActiveMQBytesMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQDestinationTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQDestinationTestSupport.java new file mode 100644 index 0000000000..f582368e03 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQDestinationTestSupport.java @@ -0,0 +1,40 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for ActiveMQDestination + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public abstract class ActiveMQDestinationTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQDestination info = (ActiveMQDestination)object; + info.setPhysicalName("PhysicalName:1"); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQMapMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQMapMessageTest.java new file mode 100644 index 0000000000..45e531afaa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQMapMessageTest.java @@ -0,0 +1,45 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQMapMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQMapMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQMapMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQMapMessageTest SINGLETON = new ActiveMQMapMessageTest(); + + public Object createObject() throws Exception { + ActiveMQMapMessage info = new ActiveMQMapMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQMapMessage info = (ActiveMQMapMessage)object; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQMessageTest.java new file mode 100644 index 0000000000..eb1d050f25 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQMessageTest extends MessageTestSupport { + + public static final ActiveMQMessageTest SINGLETON = new ActiveMQMessageTest(); + + public Object createObject() throws Exception { + ActiveMQMessage info = new ActiveMQMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQMessage info = (ActiveMQMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQObjectMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQObjectMessageTest.java new file mode 100644 index 0000000000..ddb9b1b312 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQObjectMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQObjectMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQObjectMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQObjectMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQObjectMessageTest SINGLETON = new ActiveMQObjectMessageTest(); + + public Object createObject() throws Exception { + ActiveMQObjectMessage info = new ActiveMQObjectMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQObjectMessage info = (ActiveMQObjectMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQQueueTest.java new file mode 100644 index 0000000000..453f702cad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQQueueTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQQueue; + +/** + * Test case for the OpenWire marshalling for ActiveMQQueue + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQQueueTest extends ActiveMQDestinationTestSupport { + + public static final ActiveMQQueueTest SINGLETON = new ActiveMQQueueTest(); + + public Object createObject() throws Exception { + ActiveMQQueue info = new ActiveMQQueue(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQQueue info = (ActiveMQQueue)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQStreamMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQStreamMessageTest.java new file mode 100644 index 0000000000..21ccc88139 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQStreamMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQStreamMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQStreamMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQStreamMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQStreamMessageTest SINGLETON = new ActiveMQStreamMessageTest(); + + public Object createObject() throws Exception { + ActiveMQStreamMessage info = new ActiveMQStreamMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQStreamMessage info = (ActiveMQStreamMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempDestinationTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempDestinationTestSupport.java new file mode 100644 index 0000000000..db609bfa2c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempDestinationTestSupport.java @@ -0,0 +1,38 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQTempDestination; + +/** + * Test case for the OpenWire marshalling for ActiveMQTempDestination + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public abstract class ActiveMQTempDestinationTestSupport extends ActiveMQDestinationTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTempDestination info = (ActiveMQTempDestination)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempQueueTest.java new file mode 100644 index 0000000000..817996f732 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempQueueTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQTempQueue; + +/** + * Test case for the OpenWire marshalling for ActiveMQTempQueue + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTempQueueTest extends ActiveMQTempDestinationTestSupport { + + public static final ActiveMQTempQueueTest SINGLETON = new ActiveMQTempQueueTest(); + + public Object createObject() throws Exception { + ActiveMQTempQueue info = new ActiveMQTempQueue(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTempQueue info = (ActiveMQTempQueue)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempTopicTest.java new file mode 100644 index 0000000000..b940fc50a0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTempTopicTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQTempTopic; + +/** + * Test case for the OpenWire marshalling for ActiveMQTempTopic + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTempTopicTest extends ActiveMQTempDestinationTestSupport { + + public static final ActiveMQTempTopicTest SINGLETON = new ActiveMQTempTopicTest(); + + public Object createObject() throws Exception { + ActiveMQTempTopic info = new ActiveMQTempTopic(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTempTopic info = (ActiveMQTempTopic)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTextMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTextMessageTest.java new file mode 100644 index 0000000000..0c7b7427f2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTextMessageTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQTextMessage; + +/** + * Test case for the OpenWire marshalling for ActiveMQTextMessage + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTextMessageTest extends ActiveMQMessageTest { + + public static final ActiveMQTextMessageTest SINGLETON = new ActiveMQTextMessageTest(); + + public Object createObject() throws Exception { + ActiveMQTextMessage info = new ActiveMQTextMessage(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTextMessage info = (ActiveMQTextMessage)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTopicTest.java new file mode 100644 index 0000000000..ac3e9a1e31 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ActiveMQTopicTest.java @@ -0,0 +1,46 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ActiveMQTopic; + +/** + * Test case for the OpenWire marshalling for ActiveMQTopic + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public class ActiveMQTopicTest extends ActiveMQDestinationTestSupport { + + public static final ActiveMQTopicTest SINGLETON = new ActiveMQTopicTest(); + + public Object createObject() throws Exception { + ActiveMQTopic info = new ActiveMQTopic(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ActiveMQTopic info = (ActiveMQTopic)object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BaseCommandTestSupport.java new file mode 100644 index 0000000000..5aebc4f854 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BaseCommandTestSupport.java @@ -0,0 +1,39 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BrokerIdTest.java new file mode 100644 index 0000000000..3ecb39e871 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BrokerIdTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for BrokerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerIdTest extends DataFileGeneratorTestSupport { + + + public static final BrokerIdTest SINGLETON = new BrokerIdTest(); + + public Object createObject() throws Exception { + BrokerId info = new BrokerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerId info = (BrokerId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BrokerInfoTest.java new file mode 100644 index 0000000000..5db97830f3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/BrokerInfoTest.java @@ -0,0 +1,60 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.BrokerInfo; + +/** + * Test case for the OpenWire marshalling for BrokerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class BrokerInfoTest extends BaseCommandTestSupport { + + public static final BrokerInfoTest SINGLETON = new BrokerInfoTest(); + + public Object createObject() throws Exception { + BrokerInfo info = new BrokerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerInfo info = (BrokerInfo)object; + + info.setBrokerId(createBrokerId("BrokerId:1")); + info.setBrokerURL("BrokerURL:2"); + { + BrokerInfo value[] = new BrokerInfo[0]; + for (int i = 0; i < 0; i++) { + value[i] = createBrokerInfo("PeerBrokerInfos:3"); + } + info.setPeerBrokerInfos(value); + } + info.setBrokerName("BrokerName:4"); + info.setSlaveBroker(true); + info.setMasterBroker(false); + info.setFaultTolerantConfiguration(true); + info.setDuplexConnection(false); + info.setNetworkConnection(true); + info.setConnectionId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionControlTest.java new file mode 100644 index 0000000000..5e89773be1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionControlTest.java @@ -0,0 +1,54 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ConnectionControl; + + +/** + * Test case for the OpenWire marshalling for ConnectionControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionControlTest extends BaseCommandTestSupport { + + + public static final ConnectionControlTest SINGLETON = new ConnectionControlTest(); + + public Object createObject() throws Exception { + ConnectionControl info = new ConnectionControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionControl info = (ConnectionControl) object; + + info.setClose(true); + info.setExit(false); + info.setFaultTolerant(true); + info.setResume(false); + info.setSuspend(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionErrorTest.java new file mode 100644 index 0000000000..ac5b5d9aa7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionErrorTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ConnectionError; + + +/** + * Test case for the OpenWire marshalling for ConnectionError + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionErrorTest extends BaseCommandTestSupport { + + + public static final ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); + + public Object createObject() throws Exception { + ConnectionError info = new ConnectionError(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionError info = (ConnectionError) object; + + info.setException(createThrowable("Exception:1")); + info.setConnectionId(createConnectionId("ConnectionId:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionIdTest.java new file mode 100644 index 0000000000..8e066cef7a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionIdTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for ConnectionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionIdTest extends DataFileGeneratorTestSupport { + + + public static final ConnectionIdTest SINGLETON = new ConnectionIdTest(); + + public Object createObject() throws Exception { + ConnectionId info = new ConnectionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionId info = (ConnectionId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionInfoTest.java new file mode 100644 index 0000000000..82fb37d3b2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConnectionInfoTest.java @@ -0,0 +1,59 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ConnectionInfo; + +/** + * Test case for the OpenWire marshalling for ConnectionInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ConnectionInfoTest extends BaseCommandTestSupport { + + public static final ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); + + public Object createObject() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionInfo info = (ConnectionInfo)object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setClientId("ClientId:2"); + info.setPassword("Password:3"); + info.setUserName("UserName:4"); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setBrokerMasterConnector(true); + info.setManageable(false); + info.setClientMaster(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerControlTest.java new file mode 100644 index 0000000000..b5505331a4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerControlTest.java @@ -0,0 +1,55 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ConsumerControl; + + +/** + * Test case for the OpenWire marshalling for ConsumerControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerControlTest extends BaseCommandTestSupport { + + + public static final ConsumerControlTest SINGLETON = new ConsumerControlTest(); + + public Object createObject() throws Exception { + ConsumerControl info = new ConsumerControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerControl info = (ConsumerControl) object; + + info.setClose(true); + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setPrefetch(1); + info.setFlush(false); + info.setStart(true); + info.setStop(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerIdTest.java new file mode 100644 index 0000000000..d818c853c0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerIdTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for ConsumerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerIdTest extends DataFileGeneratorTestSupport { + + + public static final ConsumerIdTest SINGLETON = new ConsumerIdTest(); + + public Object createObject() throws Exception { + ConsumerId info = new ConsumerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerId info = (ConsumerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setSessionId(1); + info.setValue(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerInfoTest.java new file mode 100644 index 0000000000..1420260a92 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ConsumerInfoTest.java @@ -0,0 +1,68 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ConsumerInfo; + +/** + * Test case for the OpenWire marshalling for ConsumerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ConsumerInfoTest extends BaseCommandTestSupport { + + public static final ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); + + public Object createObject() throws Exception { + ConsumerInfo info = new ConsumerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerInfo info = (ConsumerInfo)object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setBrowser(true); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setPrefetchSize(1); + info.setMaximumPendingMessageLimit(2); + info.setDispatchAsync(false); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubscriptionName:4"); + info.setNoLocal(true); + info.setExclusive(false); + info.setRetroactive(true); + info.setPriority((byte)1); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); + info.setNetworkSubscription(false); + info.setOptimizedAcknowledge(true); + info.setNoRangeAcks(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ControlCommandTest.java new file mode 100644 index 0000000000..776726718e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ControlCommandTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ControlCommand; + + +/** + * Test case for the OpenWire marshalling for ControlCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ControlCommandTest extends BaseCommandTestSupport { + + + public static final ControlCommandTest SINGLETON = new ControlCommandTest(); + + public Object createObject() throws Exception { + ControlCommand info = new ControlCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ControlCommand info = (ControlCommand) object; + + info.setCommand("Command:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DataArrayResponseTest.java new file mode 100644 index 0000000000..3398dff6be --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DataArrayResponseTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.DataArrayResponse; +import org.apache.activemq.command.DataStructure; + +/** + * Test case for the OpenWire marshalling for DataArrayResponse NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class DataArrayResponseTest extends ResponseTest { + + public static final DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); + + public Object createObject() throws Exception { + DataArrayResponse info = new DataArrayResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataArrayResponse info = (DataArrayResponse)object; + + { + DataStructure value[] = new DataStructure[2]; + for (int i = 0; i < 2; i++) { + value[i] = createDataStructure("Data:1"); + } + info.setData(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DataResponseTest.java new file mode 100644 index 0000000000..f8b4e495bb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DataResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.DataResponse; + + +/** + * Test case for the OpenWire marshalling for DataResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataResponseTest extends ResponseTest { + + + public static final DataResponseTest SINGLETON = new DataResponseTest(); + + public Object createObject() throws Exception { + DataResponse info = new DataResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataResponse info = (DataResponse) object; + + info.setData(createDataStructure("Data:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DestinationInfoTest.java new file mode 100644 index 0000000000..accfb0b7a6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DestinationInfoTest.java @@ -0,0 +1,56 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.DestinationInfo; + +/** + * Test case for the OpenWire marshalling for DestinationInfo NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class DestinationInfoTest extends BaseCommandTestSupport { + + public static final DestinationInfoTest SINGLETON = new DestinationInfoTest(); + + public Object createObject() throws Exception { + DestinationInfo info = new DestinationInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DestinationInfo info = (DestinationInfo)object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setOperationType((byte)1); + info.setTimeout(1); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DiscoveryEventTest.java new file mode 100644 index 0000000000..77dca5f9e0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/DiscoveryEventTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.DiscoveryEvent; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for DiscoveryEvent + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DiscoveryEventTest extends DataFileGeneratorTestSupport { + + + public static final DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); + + public Object createObject() throws Exception { + DiscoveryEvent info = new DiscoveryEvent(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DiscoveryEvent info = (DiscoveryEvent) object; + + info.setServiceName("ServiceName:1"); + info.setBrokerName("BrokerName:2"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ExceptionResponseTest.java new file mode 100644 index 0000000000..0f81fc7a6c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ExceptionResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ExceptionResponse; + + +/** + * Test case for the OpenWire marshalling for ExceptionResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ExceptionResponseTest extends ResponseTest { + + + public static final ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); + + public Object createObject() throws Exception { + ExceptionResponse info = new ExceptionResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ExceptionResponse info = (ExceptionResponse) object; + + info.setException(createThrowable("Exception:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/FlushCommandTest.java new file mode 100644 index 0000000000..c00826b783 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/FlushCommandTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.FlushCommand; + + +/** + * Test case for the OpenWire marshalling for FlushCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class FlushCommandTest extends BaseCommandTestSupport { + + + public static final FlushCommandTest SINGLETON = new FlushCommandTest(); + + public Object createObject() throws Exception { + FlushCommand info = new FlushCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + FlushCommand info = (FlushCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/IntegerResponseTest.java new file mode 100644 index 0000000000..171303b061 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/IntegerResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.IntegerResponse; + + +/** + * Test case for the OpenWire marshalling for IntegerResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class IntegerResponseTest extends ResponseTest { + + + public static final IntegerResponseTest SINGLETON = new IntegerResponseTest(); + + public Object createObject() throws Exception { + IntegerResponse info = new IntegerResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + IntegerResponse info = (IntegerResponse) object; + + info.setResult(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalQueueAckTest.java new file mode 100644 index 0000000000..5613a992e3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalQueueAckTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.JournalQueueAck; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalQueueAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalQueueAckTest extends DataFileGeneratorTestSupport { + + + public static final JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); + + public Object createObject() throws Exception { + JournalQueueAck info = new JournalQueueAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalQueueAck info = (JournalQueueAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageAck(createMessageAck("MessageAck:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTopicAckTest.java new file mode 100644 index 0000000000..022180212b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTopicAckTest.java @@ -0,0 +1,56 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.JournalTopicAck; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalTopicAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTopicAckTest extends DataFileGeneratorTestSupport { + + + public static final JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); + + public Object createObject() throws Exception { + JournalTopicAck info = new JournalTopicAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTopicAck info = (JournalTopicAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageId(createMessageId("MessageId:2")); + info.setMessageSequenceId(1); + info.setSubscritionName("SubscritionName:3"); + info.setClientId("ClientId:4"); + info.setTransactionId(createTransactionId("TransactionId:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTraceTest.java new file mode 100644 index 0000000000..e0ac05c0ed --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTraceTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.JournalTrace; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalTrace + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTraceTest extends DataFileGeneratorTestSupport { + + + public static final JournalTraceTest SINGLETON = new JournalTraceTest(); + + public Object createObject() throws Exception { + JournalTrace info = new JournalTrace(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTrace info = (JournalTrace) object; + + info.setMessage("Message:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTransactionTest.java new file mode 100644 index 0000000000..714a697fed --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/JournalTransactionTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.JournalTransaction; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalTransaction + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTransactionTest extends DataFileGeneratorTestSupport { + + + public static final JournalTransactionTest SINGLETON = new JournalTransactionTest(); + + public Object createObject() throws Exception { + JournalTransaction info = new JournalTransaction(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTransaction info = (JournalTransaction) object; + + info.setTransactionId(createTransactionId("TransactionId:1")); + info.setType((byte) 1); + info.setWasPrepared(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/KeepAliveInfoTest.java new file mode 100644 index 0000000000..b20eb451ff --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/KeepAliveInfoTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.KeepAliveInfo; + + +/** + * Test case for the OpenWire marshalling for KeepAliveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class KeepAliveInfoTest extends BaseCommandTestSupport { + + + public static final KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); + + public Object createObject() throws Exception { + KeepAliveInfo info = new KeepAliveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + KeepAliveInfo info = (KeepAliveInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/LastPartialCommandTest.java new file mode 100644 index 0000000000..5891acdc9c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/LastPartialCommandTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.LastPartialCommand; + + +/** + * Test case for the OpenWire marshalling for LastPartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LastPartialCommandTest extends PartialCommandTest { + + + public static final LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); + + public Object createObject() throws Exception { + LastPartialCommand info = new LastPartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LastPartialCommand info = (LastPartialCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/LocalTransactionIdTest.java new file mode 100644 index 0000000000..26748019c5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/LocalTransactionIdTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.LocalTransactionId; + + +/** + * Test case for the OpenWire marshalling for LocalTransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LocalTransactionIdTest extends TransactionIdTestSupport { + + + public static final LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); + + public Object createObject() throws Exception { + LocalTransactionId info = new LocalTransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LocalTransactionId info = (LocalTransactionId) object; + + info.setValue(1); + info.setConnectionId(createConnectionId("ConnectionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageAckTest.java new file mode 100644 index 0000000000..c4ac0155e6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageAckTest.java @@ -0,0 +1,56 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.MessageAck; + + +/** + * Test case for the OpenWire marshalling for MessageAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageAckTest extends BaseCommandTestSupport { + + + public static final MessageAckTest SINGLETON = new MessageAckTest(); + + public Object createObject() throws Exception { + MessageAck info = new MessageAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageAck info = (MessageAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setConsumerId(createConsumerId("ConsumerId:3")); + info.setAckType((byte) 1); + info.setFirstMessageId(createMessageId("FirstMessageId:4")); + info.setLastMessageId(createMessageId("LastMessageId:5")); + info.setMessageCount(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..adfe131e95 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageDispatchNotificationTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.MessageDispatchNotification; + + +/** + * Test case for the OpenWire marshalling for MessageDispatchNotification + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchNotificationTest extends BaseCommandTestSupport { + + + public static final MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); + + public Object createObject() throws Exception { + MessageDispatchNotification info = new MessageDispatchNotification(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatchNotification info = (MessageDispatchNotification) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setDeliverySequenceId(1); + info.setMessageId(createMessageId("MessageId:3")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageDispatchTest.java new file mode 100644 index 0000000000..b100da32bb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageDispatchTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.MessageDispatch; + + +/** + * Test case for the OpenWire marshalling for MessageDispatch + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchTest extends BaseCommandTestSupport { + + + public static final MessageDispatchTest SINGLETON = new MessageDispatchTest(); + + public Object createObject() throws Exception { + MessageDispatch info = new MessageDispatch(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatch info = (MessageDispatch) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setMessage(createMessage("Message:3")); + info.setRedeliveryCounter(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageIdTest.java new file mode 100644 index 0000000000..bc4af3798d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageIdTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.MessageId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for MessageId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageIdTest extends DataFileGeneratorTestSupport { + + + public static final MessageIdTest SINGLETON = new MessageIdTest(); + + public Object createObject() throws Exception { + MessageId info = new MessageId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageId info = (MessageId) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setProducerSequenceId(1); + info.setBrokerSequenceId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessagePullTest.java new file mode 100644 index 0000000000..030574dcea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessagePullTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.MessagePull; + + +/** + * Test case for the OpenWire marshalling for MessagePull + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessagePullTest extends BaseCommandTestSupport { + + + public static final MessagePullTest SINGLETON = new MessagePullTest(); + + public Object createObject() throws Exception { + MessagePull info = new MessagePull(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessagePull info = (MessagePull) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTimeout(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageTestSupport.java new file mode 100644 index 0000000000..09bbd95df1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/MessageTestSupport.java @@ -0,0 +1,89 @@ +/** + * 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.openwire.v2; + +import java.io.DataOutputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.Message; +import org.apache.activemq.util.ByteArrayOutputStream; +import org.apache.activemq.util.MarshallingSupport; + +/** + * Test case for the OpenWire marshalling for Message NOTE!: This file is auto + * generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public abstract class MessageTestSupport extends BaseCommandTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Message info = (Message)object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTransactionId(createTransactionId("TransactionId:3")); + info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); + info.setMessageId(createMessageId("MessageId:5")); + info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); + info.setGroupID("GroupID:7"); + info.setGroupSequence(1); + info.setCorrelationId("CorrelationId:8"); + info.setPersistent(true); + info.setExpiration(1); + info.setPriority((byte)1); + info.setReplyTo(createActiveMQDestination("ReplyTo:9")); + info.setTimestamp(2); + info.setType("Type:10"); + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dataOut = new DataOutputStream(baos); + MarshallingSupport.writeUTF8(dataOut, "Content:11"); + dataOut.close(); + info.setContent(baos.toByteSequence()); + } + { + Map map = new HashMap(); + map.put("MarshalledProperties", 12); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + MarshallingSupport.marshalPrimitiveMap(map, os); + os.close(); + info.setMarshalledProperties(baos.toByteSequence()); + } + info.setDataStructure(createDataStructure("DataStructure:13")); + info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); + info.setCompressed(false); + info.setRedeliveryCounter(2); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:15"); + } + info.setBrokerPath(value); + } + info.setArrival(3); + info.setUserID("UserID:16"); + info.setRecievedByDFBridge(true); + info.setDroppable(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..6afa4ef513 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/NetworkBridgeFilterTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.NetworkBridgeFilter; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for NetworkBridgeFilter + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { + + + public static final NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); + + public Object createObject() throws Exception { + NetworkBridgeFilter info = new NetworkBridgeFilter(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + NetworkBridgeFilter info = (NetworkBridgeFilter) object; + + info.setNetworkTTL(1); + info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/PartialCommandTest.java new file mode 100644 index 0000000000..38e245f55d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/PartialCommandTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.PartialCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for PartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class PartialCommandTest extends DataFileGeneratorTestSupport { + + + public static final PartialCommandTest SINGLETON = new PartialCommandTest(); + + public Object createObject() throws Exception { + PartialCommand info = new PartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + PartialCommand info = (PartialCommand) object; + + info.setCommandId(1); + info.setData("Data:1".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ProducerIdTest.java new file mode 100644 index 0000000000..cbe32f878b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ProducerIdTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for ProducerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerIdTest extends DataFileGeneratorTestSupport { + + + public static final ProducerIdTest SINGLETON = new ProducerIdTest(); + + public Object createObject() throws Exception { + ProducerId info = new ProducerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerId info = (ProducerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + info.setSessionId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ProducerInfoTest.java new file mode 100644 index 0000000000..07e226b56f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ProducerInfoTest.java @@ -0,0 +1,55 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ProducerInfo; + +/** + * Test case for the OpenWire marshalling for ProducerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ProducerInfoTest extends BaseCommandTestSupport { + + public static final ProducerInfoTest SINGLETON = new ProducerInfoTest(); + + public Object createObject() throws Exception { + ProducerInfo info = new ProducerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerInfo info = (ProducerInfo)object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + info.setDispatchAsync(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/RemoveInfoTest.java new file mode 100644 index 0000000000..c45e7df61d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/RemoveInfoTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.RemoveInfo; + + +/** + * Test case for the OpenWire marshalling for RemoveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveInfoTest extends BaseCommandTestSupport { + + + public static final RemoveInfoTest SINGLETON = new RemoveInfoTest(); + + public Object createObject() throws Exception { + RemoveInfo info = new RemoveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveInfo info = (RemoveInfo) object; + + info.setObjectId(createDataStructure("ObjectId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..4c30153a1f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/RemoveSubscriptionInfoTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.RemoveSubscriptionInfo; + + +/** + * Test case for the OpenWire marshalling for RemoveSubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { + + + public static final RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); + + public Object createObject() throws Exception { + RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setSubscriptionName("SubcriptionName:2"); + info.setClientId("ClientId:3"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ReplayCommandTest.java new file mode 100644 index 0000000000..a2d821cf23 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ReplayCommandTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ReplayCommand; + + +/** + * Test case for the OpenWire marshalling for ReplayCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ReplayCommandTest extends BaseCommandTestSupport { + + + public static final ReplayCommandTest SINGLETON = new ReplayCommandTest(); + + public Object createObject() throws Exception { + ReplayCommand info = new ReplayCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ReplayCommand info = (ReplayCommand) object; + + info.setFirstNakNumber(1); + info.setLastNakNumber(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ResponseTest.java new file mode 100644 index 0000000000..0cde5777d9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.Response; + + +/** + * Test case for the OpenWire marshalling for Response + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ResponseTest extends BaseCommandTestSupport { + + + public static final ResponseTest SINGLETON = new ResponseTest(); + + public Object createObject() throws Exception { + Response info = new Response(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Response info = (Response) object; + + info.setCorrelationId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SessionIdTest.java new file mode 100644 index 0000000000..50d896f4e2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SessionIdTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.SessionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for SessionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionIdTest extends DataFileGeneratorTestSupport { + + + public static final SessionIdTest SINGLETON = new SessionIdTest(); + + public Object createObject() throws Exception { + SessionId info = new SessionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionId info = (SessionId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SessionInfoTest.java new file mode 100644 index 0000000000..233f37dfb3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SessionInfoTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.SessionInfo; + + +/** + * Test case for the OpenWire marshalling for SessionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionInfoTest extends BaseCommandTestSupport { + + + public static final SessionInfoTest SINGLETON = new SessionInfoTest(); + + public Object createObject() throws Exception { + SessionInfo info = new SessionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionInfo info = (SessionInfo) object; + + info.setSessionId(createSessionId("SessionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ShutdownInfoTest.java new file mode 100644 index 0000000000..f617f145b3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/ShutdownInfoTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.ShutdownInfo; + + +/** + * Test case for the OpenWire marshalling for ShutdownInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ShutdownInfoTest extends BaseCommandTestSupport { + + + public static final ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); + + public Object createObject() throws Exception { + ShutdownInfo info = new ShutdownInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ShutdownInfo info = (ShutdownInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SubscriptionInfoTest.java new file mode 100644 index 0000000000..f34f962420 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/SubscriptionInfoTest.java @@ -0,0 +1,54 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.SubscriptionInfo; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for SubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { + + + public static final SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); + + public Object createObject() throws Exception { + SubscriptionInfo info = new SubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SubscriptionInfo info = (SubscriptionInfo) object; + + info.setClientId("ClientId:1"); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubcriptionName:4"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/TransactionIdTestSupport.java new file mode 100644 index 0000000000..ffa7eb1100 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/TransactionIdTestSupport.java @@ -0,0 +1,42 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for TransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionId info = (TransactionId) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/TransactionInfoTest.java new file mode 100644 index 0000000000..128fde8c59 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/TransactionInfoTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.TransactionInfo; + + +/** + * Test case for the OpenWire marshalling for TransactionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class TransactionInfoTest extends BaseCommandTestSupport { + + + public static final TransactionInfoTest SINGLETON = new TransactionInfoTest(); + + public Object createObject() throws Exception { + TransactionInfo info = new TransactionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionInfo info = (TransactionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setType((byte) 1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/WireFormatInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/WireFormatInfoTest.java new file mode 100644 index 0000000000..4eba697890 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/WireFormatInfoTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.WireFormatInfo; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for WireFormatInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class WireFormatInfoTest extends DataFileGeneratorTestSupport { + + public static final WireFormatInfoTest SINGLETON = new WireFormatInfoTest(); + + public Object createObject() throws Exception { + WireFormatInfo info = new WireFormatInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + WireFormatInfo info = (WireFormatInfo)object; + info.setVersion(1); + + { + byte data[] = "MarshalledProperties:1".getBytes(); + info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data, 0, data.length)); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/XATransactionIdTest.java new file mode 100644 index 0000000000..d266111351 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v2/XATransactionIdTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v2; + +import org.apache.activemq.command.XATransactionId; + + +/** + * Test case for the OpenWire marshalling for XATransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class XATransactionIdTest extends TransactionIdTestSupport { + + + public static final XATransactionIdTest SINGLETON = new XATransactionIdTest(); + + public Object createObject() throws Exception { + XATransactionId info = new XATransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + XATransactionId info = (XATransactionId) object; + + info.setFormatId(1); + info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); + info.setBranchQualifier("BranchQualifier:2".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BaseCommandTestSupport.java new file mode 100644 index 0000000000..628d34c753 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BaseCommandTestSupport.java @@ -0,0 +1,41 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand + * + * + * NOTE!: This file is auto generated - do not modify! if you need to make a + * change, please see the modify the groovy scripts in the under src/gram/script + * and then use maven openwire:generate to regenerate this file. + * + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BrokerIdTest.java new file mode 100644 index 0000000000..b3ed358b5a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BrokerIdTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for BrokerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerIdTest extends DataFileGeneratorTestSupport { + + + public static final BrokerIdTest SINGLETON = new BrokerIdTest(); + + public Object createObject() throws Exception { + BrokerId info = new BrokerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerId info = (BrokerId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BrokerInfoTest.java new file mode 100644 index 0000000000..a7bede2d1f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/BrokerInfoTest.java @@ -0,0 +1,62 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BrokerInfo; + +/** + * Test case for the OpenWire marshalling for BrokerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class BrokerInfoTest extends BaseCommandTestSupport { + + public static final BrokerInfoTest SINGLETON = new BrokerInfoTest(); + + public Object createObject() throws Exception { + BrokerInfo info = new BrokerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerInfo info = (BrokerInfo)object; + + info.setBrokerId(createBrokerId("BrokerId:1")); + info.setBrokerURL("BrokerURL:2"); + { + BrokerInfo value[] = new BrokerInfo[0]; + for (int i = 0; i < 0; i++) { + value[i] = createBrokerInfo("PeerBrokerInfos:3"); + } + info.setPeerBrokerInfos(value); + } + info.setBrokerName("BrokerName:4"); + info.setSlaveBroker(true); + info.setMasterBroker(false); + info.setFaultTolerantConfiguration(true); + info.setDuplexConnection(false); + info.setNetworkConnection(true); + info.setConnectionId(1); + info.setBrokerUploadUrl("BrokerUploadUrl:5"); + info.setNetworkProperties("NetworkProperties:6"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionControlTest.java new file mode 100644 index 0000000000..ec7a10990e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionControlTest.java @@ -0,0 +1,54 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ConnectionControl; + + +/** + * Test case for the OpenWire marshalling for ConnectionControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionControlTest extends BaseCommandTestSupport { + + + public static final ConnectionControlTest SINGLETON = new ConnectionControlTest(); + + public Object createObject() throws Exception { + ConnectionControl info = new ConnectionControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionControl info = (ConnectionControl) object; + + info.setClose(true); + info.setExit(false); + info.setFaultTolerant(true); + info.setResume(false); + info.setSuspend(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionErrorTest.java new file mode 100644 index 0000000000..dd19044313 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionErrorTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ConnectionError; + + +/** + * Test case for the OpenWire marshalling for ConnectionError + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionErrorTest extends BaseCommandTestSupport { + + + public static final ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); + + public Object createObject() throws Exception { + ConnectionError info = new ConnectionError(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionError info = (ConnectionError) object; + + info.setException(createThrowable("Exception:1")); + info.setConnectionId(createConnectionId("ConnectionId:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionIdTest.java new file mode 100644 index 0000000000..05b5430dde --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionIdTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for ConnectionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionIdTest extends DataFileGeneratorTestSupport { + + + public static final ConnectionIdTest SINGLETON = new ConnectionIdTest(); + + public Object createObject() throws Exception { + ConnectionId info = new ConnectionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionId info = (ConnectionId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionInfoTest.java new file mode 100644 index 0000000000..78f0729f6c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConnectionInfoTest.java @@ -0,0 +1,59 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ConnectionInfo; + +/** + * Test case for the OpenWire marshalling for ConnectionInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ConnectionInfoTest extends BaseCommandTestSupport { + + public static final ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); + + public Object createObject() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionInfo info = (ConnectionInfo)object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setClientId("ClientId:2"); + info.setPassword("Password:3"); + info.setUserName("UserName:4"); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setBrokerMasterConnector(true); + info.setManageable(false); + info.setClientMaster(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerControlTest.java new file mode 100644 index 0000000000..7f061c875e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerControlTest.java @@ -0,0 +1,55 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ConsumerControl; + + +/** + * Test case for the OpenWire marshalling for ConsumerControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerControlTest extends BaseCommandTestSupport { + + + public static final ConsumerControlTest SINGLETON = new ConsumerControlTest(); + + public Object createObject() throws Exception { + ConsumerControl info = new ConsumerControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerControl info = (ConsumerControl) object; + + info.setClose(true); + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setPrefetch(1); + info.setFlush(false); + info.setStart(true); + info.setStop(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerIdTest.java new file mode 100644 index 0000000000..54cc8da812 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerIdTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ConsumerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for ConsumerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerIdTest extends DataFileGeneratorTestSupport { + + + public static final ConsumerIdTest SINGLETON = new ConsumerIdTest(); + + public Object createObject() throws Exception { + ConsumerId info = new ConsumerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerId info = (ConsumerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setSessionId(1); + info.setValue(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerInfoTest.java new file mode 100644 index 0000000000..24d00d601a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ConsumerInfoTest.java @@ -0,0 +1,68 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ConsumerInfo; + +/** + * Test case for the OpenWire marshalling for ConsumerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ConsumerInfoTest extends BaseCommandTestSupport { + + public static final ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); + + public Object createObject() throws Exception { + ConsumerInfo info = new ConsumerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerInfo info = (ConsumerInfo)object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setBrowser(true); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setPrefetchSize(1); + info.setMaximumPendingMessageLimit(2); + info.setDispatchAsync(false); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubscriptionName:4"); + info.setNoLocal(true); + info.setExclusive(false); + info.setRetroactive(true); + info.setPriority((byte)1); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); + info.setNetworkSubscription(false); + info.setOptimizedAcknowledge(true); + info.setNoRangeAcks(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ControlCommandTest.java new file mode 100644 index 0000000000..401fe68ee9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ControlCommandTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ControlCommand; + + +/** + * Test case for the OpenWire marshalling for ControlCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ControlCommandTest extends BaseCommandTestSupport { + + + public static final ControlCommandTest SINGLETON = new ControlCommandTest(); + + public Object createObject() throws Exception { + ControlCommand info = new ControlCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ControlCommand info = (ControlCommand) object; + + info.setCommand("Command:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DataArrayResponseTest.java new file mode 100644 index 0000000000..b6f3a87dc0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DataArrayResponseTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.DataArrayResponse; +import org.apache.activemq.command.DataStructure; + +/** + * Test case for the OpenWire marshalling for DataArrayResponse NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class DataArrayResponseTest extends ResponseTest { + + public static final DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); + + public Object createObject() throws Exception { + DataArrayResponse info = new DataArrayResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataArrayResponse info = (DataArrayResponse)object; + + { + DataStructure value[] = new DataStructure[2]; + for (int i = 0; i < 2; i++) { + value[i] = createDataStructure("Data:1"); + } + info.setData(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DataResponseTest.java new file mode 100644 index 0000000000..cf773a5a42 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DataResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.DataResponse; + + +/** + * Test case for the OpenWire marshalling for DataResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataResponseTest extends ResponseTest { + + + public static final DataResponseTest SINGLETON = new DataResponseTest(); + + public Object createObject() throws Exception { + DataResponse info = new DataResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataResponse info = (DataResponse) object; + + info.setData(createDataStructure("Data:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DestinationInfoTest.java new file mode 100644 index 0000000000..d7f7343003 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DestinationInfoTest.java @@ -0,0 +1,56 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.DestinationInfo; + +/** + * Test case for the OpenWire marshalling for DestinationInfo NOTE!: This file + * is auto generated - do not modify! if you need to make a change, please see + * the modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class DestinationInfoTest extends BaseCommandTestSupport { + + public static final DestinationInfoTest SINGLETON = new DestinationInfoTest(); + + public Object createObject() throws Exception { + DestinationInfo info = new DestinationInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DestinationInfo info = (DestinationInfo)object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setOperationType((byte)1); + info.setTimeout(1); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DiscoveryEventTest.java new file mode 100644 index 0000000000..173801ec9f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/DiscoveryEventTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.DiscoveryEvent; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for DiscoveryEvent + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DiscoveryEventTest extends DataFileGeneratorTestSupport { + + + public static final DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); + + public Object createObject() throws Exception { + DiscoveryEvent info = new DiscoveryEvent(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DiscoveryEvent info = (DiscoveryEvent) object; + + info.setServiceName("ServiceName:1"); + info.setBrokerName("BrokerName:2"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ExceptionResponseTest.java new file mode 100644 index 0000000000..9c2edb36e8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ExceptionResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ExceptionResponse; + + +/** + * Test case for the OpenWire marshalling for ExceptionResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ExceptionResponseTest extends ResponseTest { + + + public static final ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); + + public Object createObject() throws Exception { + ExceptionResponse info = new ExceptionResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ExceptionResponse info = (ExceptionResponse) object; + + info.setException(createThrowable("Exception:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/FlushCommandTest.java new file mode 100644 index 0000000000..ac16ffb37e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/FlushCommandTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.FlushCommand; + + +/** + * Test case for the OpenWire marshalling for FlushCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class FlushCommandTest extends BaseCommandTestSupport { + + + public static final FlushCommandTest SINGLETON = new FlushCommandTest(); + + public Object createObject() throws Exception { + FlushCommand info = new FlushCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + FlushCommand info = (FlushCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/IntegerResponseTest.java new file mode 100644 index 0000000000..6db78d1c1d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/IntegerResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.IntegerResponse; + + +/** + * Test case for the OpenWire marshalling for IntegerResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class IntegerResponseTest extends ResponseTest { + + + public static final IntegerResponseTest SINGLETON = new IntegerResponseTest(); + + public Object createObject() throws Exception { + IntegerResponse info = new IntegerResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + IntegerResponse info = (IntegerResponse) object; + + info.setResult(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalQueueAckTest.java new file mode 100644 index 0000000000..1cdfa0a472 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalQueueAckTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.JournalQueueAck; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalQueueAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalQueueAckTest extends DataFileGeneratorTestSupport { + + + public static final JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); + + public Object createObject() throws Exception { + JournalQueueAck info = new JournalQueueAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalQueueAck info = (JournalQueueAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageAck(createMessageAck("MessageAck:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTopicAckTest.java new file mode 100644 index 0000000000..e9b826adac --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTopicAckTest.java @@ -0,0 +1,56 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.JournalTopicAck; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalTopicAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTopicAckTest extends DataFileGeneratorTestSupport { + + + public static final JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); + + public Object createObject() throws Exception { + JournalTopicAck info = new JournalTopicAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTopicAck info = (JournalTopicAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageId(createMessageId("MessageId:2")); + info.setMessageSequenceId(1); + info.setSubscritionName("SubscritionName:3"); + info.setClientId("ClientId:4"); + info.setTransactionId(createTransactionId("TransactionId:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTraceTest.java new file mode 100644 index 0000000000..6cfd58c332 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTraceTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.JournalTrace; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalTrace + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTraceTest extends DataFileGeneratorTestSupport { + + + public static final JournalTraceTest SINGLETON = new JournalTraceTest(); + + public Object createObject() throws Exception { + JournalTrace info = new JournalTrace(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTrace info = (JournalTrace) object; + + info.setMessage("Message:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTransactionTest.java new file mode 100644 index 0000000000..5918926f73 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/JournalTransactionTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.JournalTransaction; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for JournalTransaction + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTransactionTest extends DataFileGeneratorTestSupport { + + + public static final JournalTransactionTest SINGLETON = new JournalTransactionTest(); + + public Object createObject() throws Exception { + JournalTransaction info = new JournalTransaction(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTransaction info = (JournalTransaction) object; + + info.setTransactionId(createTransactionId("TransactionId:1")); + info.setType((byte) 1); + info.setWasPrepared(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/KeepAliveInfoTest.java new file mode 100644 index 0000000000..19896c110b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/KeepAliveInfoTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.KeepAliveInfo; + + +/** + * Test case for the OpenWire marshalling for KeepAliveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class KeepAliveInfoTest extends BaseCommandTestSupport { + + + public static final KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); + + public Object createObject() throws Exception { + KeepAliveInfo info = new KeepAliveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + KeepAliveInfo info = (KeepAliveInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/LastPartialCommandTest.java new file mode 100644 index 0000000000..eadb6d840a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/LastPartialCommandTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.LastPartialCommand; + + +/** + * Test case for the OpenWire marshalling for LastPartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LastPartialCommandTest extends PartialCommandTest { + + + public static final LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); + + public Object createObject() throws Exception { + LastPartialCommand info = new LastPartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LastPartialCommand info = (LastPartialCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/LocalTransactionIdTest.java new file mode 100644 index 0000000000..acd7678ac9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/LocalTransactionIdTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.LocalTransactionId; + + +/** + * Test case for the OpenWire marshalling for LocalTransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LocalTransactionIdTest extends TransactionIdTestSupport { + + + public static final LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); + + public Object createObject() throws Exception { + LocalTransactionId info = new LocalTransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LocalTransactionId info = (LocalTransactionId) object; + + info.setValue(1); + info.setConnectionId(createConnectionId("ConnectionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageAckTest.java new file mode 100644 index 0000000000..f67e844d84 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageAckTest.java @@ -0,0 +1,56 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.MessageAck; + + +/** + * Test case for the OpenWire marshalling for MessageAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageAckTest extends BaseCommandTestSupport { + + + public static final MessageAckTest SINGLETON = new MessageAckTest(); + + public Object createObject() throws Exception { + MessageAck info = new MessageAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageAck info = (MessageAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setConsumerId(createConsumerId("ConsumerId:3")); + info.setAckType((byte) 1); + info.setFirstMessageId(createMessageId("FirstMessageId:4")); + info.setLastMessageId(createMessageId("LastMessageId:5")); + info.setMessageCount(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..f9a76f40be --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageDispatchNotificationTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.MessageDispatchNotification; + + +/** + * Test case for the OpenWire marshalling for MessageDispatchNotification + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchNotificationTest extends BaseCommandTestSupport { + + + public static final MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); + + public Object createObject() throws Exception { + MessageDispatchNotification info = new MessageDispatchNotification(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatchNotification info = (MessageDispatchNotification) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setDeliverySequenceId(1); + info.setMessageId(createMessageId("MessageId:3")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageDispatchTest.java new file mode 100644 index 0000000000..089218893b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageDispatchTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.MessageDispatch; + + +/** + * Test case for the OpenWire marshalling for MessageDispatch + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchTest extends BaseCommandTestSupport { + + + public static final MessageDispatchTest SINGLETON = new MessageDispatchTest(); + + public Object createObject() throws Exception { + MessageDispatch info = new MessageDispatch(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatch info = (MessageDispatch) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setMessage(createMessage("Message:3")); + info.setRedeliveryCounter(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageIdTest.java new file mode 100644 index 0000000000..8f4da88954 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageIdTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.MessageId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for MessageId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageIdTest extends DataFileGeneratorTestSupport { + + + public static final MessageIdTest SINGLETON = new MessageIdTest(); + + public Object createObject() throws Exception { + MessageId info = new MessageId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageId info = (MessageId) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setProducerSequenceId(1); + info.setBrokerSequenceId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessagePullTest.java new file mode 100644 index 0000000000..2c628fa6a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessagePullTest.java @@ -0,0 +1,54 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.MessagePull; + + +/** + * Test case for the OpenWire marshalling for MessagePull + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessagePullTest extends BaseCommandTestSupport { + + + public static final MessagePullTest SINGLETON = new MessagePullTest(); + + public Object createObject() throws Exception { + MessagePull info = new MessagePull(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessagePull info = (MessagePull) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTimeout(1); + info.setCorrelationId("CorrelationId:3"); + info.setMessageId(createMessageId("MessageId:4")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageTestSupport.java new file mode 100644 index 0000000000..20feff1c07 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/MessageTestSupport.java @@ -0,0 +1,84 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.Message; + +/** + * Test case for the OpenWire marshalling for Message NOTE!: This file is auto + * generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public abstract class MessageTestSupport extends BaseCommandTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Message info = (Message)object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTransactionId(createTransactionId("TransactionId:3")); + info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); + info.setMessageId(createMessageId("MessageId:5")); + info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); + info.setGroupID("GroupID:7"); + info.setGroupSequence(1); + info.setCorrelationId("CorrelationId:8"); + info.setPersistent(true); + info.setExpiration(1); + info.setPriority((byte)1); + info.setReplyTo(createActiveMQDestination("ReplyTo:9")); + info.setTimestamp(2); + info.setType("Type:10"); + { + byte data[] = "Content:11".getBytes(); + info.setContent(new org.apache.activemq.util.ByteSequence(data, 0, data.length)); + } + { + byte data[] = "MarshalledProperties:12".getBytes(); + info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data, 0, data.length)); + } + info.setDataStructure(createDataStructure("DataStructure:13")); + info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); + info.setCompressed(false); + info.setRedeliveryCounter(2); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:15"); + } + info.setBrokerPath(value); + } + info.setArrival(3); + info.setUserID("UserID:16"); + info.setRecievedByDFBridge(true); + info.setDroppable(false); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("Cluster:17"); + } + info.setCluster(value); + } + info.setBrokerInTime(4); + info.setBrokerOutTime(5); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..19cb220487 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/NetworkBridgeFilterTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.NetworkBridgeFilter; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for NetworkBridgeFilter + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { + + + public static final NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); + + public Object createObject() throws Exception { + NetworkBridgeFilter info = new NetworkBridgeFilter(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + NetworkBridgeFilter info = (NetworkBridgeFilter) object; + + info.setNetworkTTL(1); + info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/PartialCommandTest.java new file mode 100644 index 0000000000..6ad3f409b8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/PartialCommandTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.PartialCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for PartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class PartialCommandTest extends DataFileGeneratorTestSupport { + + + public static final PartialCommandTest SINGLETON = new PartialCommandTest(); + + public Object createObject() throws Exception { + PartialCommand info = new PartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + PartialCommand info = (PartialCommand) object; + + info.setCommandId(1); + info.setData("Data:1".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerAckTest.java new file mode 100644 index 0000000000..cd3610d071 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerAckTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ProducerAck; + + +/** + * Test case for the OpenWire marshalling for ProducerAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerAckTest extends BaseCommandTestSupport { + + + public static final ProducerAckTest SINGLETON = new ProducerAckTest(); + + public Object createObject() throws Exception { + ProducerAck info = new ProducerAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerAck info = (ProducerAck) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerIdTest.java new file mode 100644 index 0000000000..438754437b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerIdTest.java @@ -0,0 +1,53 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ProducerId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for ProducerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerIdTest extends DataFileGeneratorTestSupport { + + + public static final ProducerIdTest SINGLETON = new ProducerIdTest(); + + public Object createObject() throws Exception { + ProducerId info = new ProducerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerId info = (ProducerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + info.setSessionId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerInfoTest.java new file mode 100644 index 0000000000..4fbf05f058 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ProducerInfoTest.java @@ -0,0 +1,56 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.BrokerId; +import org.apache.activemq.command.ProducerInfo; + +/** + * Test case for the OpenWire marshalling for ProducerInfo NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public class ProducerInfoTest extends BaseCommandTestSupport { + + public static final ProducerInfoTest SINGLETON = new ProducerInfoTest(); + + public Object createObject() throws Exception { + ProducerInfo info = new ProducerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerInfo info = (ProducerInfo)object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + { + BrokerId value[] = new BrokerId[2]; + for (int i = 0; i < 2; i++) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + info.setDispatchAsync(true); + info.setWindowSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/RemoveInfoTest.java new file mode 100644 index 0000000000..7bc480e061 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/RemoveInfoTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.RemoveInfo; + + +/** + * Test case for the OpenWire marshalling for RemoveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveInfoTest extends BaseCommandTestSupport { + + + public static final RemoveInfoTest SINGLETON = new RemoveInfoTest(); + + public Object createObject() throws Exception { + RemoveInfo info = new RemoveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveInfo info = (RemoveInfo) object; + + info.setObjectId(createDataStructure("ObjectId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..2c85ef223c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/RemoveSubscriptionInfoTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.RemoveSubscriptionInfo; + + +/** + * Test case for the OpenWire marshalling for RemoveSubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { + + + public static final RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); + + public Object createObject() throws Exception { + RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setSubscriptionName("SubcriptionName:2"); + info.setClientId("ClientId:3"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ReplayCommandTest.java new file mode 100644 index 0000000000..9e4c337fb8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ReplayCommandTest.java @@ -0,0 +1,51 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ReplayCommand; + + +/** + * Test case for the OpenWire marshalling for ReplayCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ReplayCommandTest extends BaseCommandTestSupport { + + + public static final ReplayCommandTest SINGLETON = new ReplayCommandTest(); + + public Object createObject() throws Exception { + ReplayCommand info = new ReplayCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ReplayCommand info = (ReplayCommand) object; + + info.setFirstNakNumber(1); + info.setLastNakNumber(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ResponseTest.java new file mode 100644 index 0000000000..7dd6543918 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ResponseTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.Response; + + +/** + * Test case for the OpenWire marshalling for Response + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ResponseTest extends BaseCommandTestSupport { + + + public static final ResponseTest SINGLETON = new ResponseTest(); + + public Object createObject() throws Exception { + Response info = new Response(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Response info = (Response) object; + + info.setCorrelationId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SessionIdTest.java new file mode 100644 index 0000000000..136956ab95 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SessionIdTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.SessionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for SessionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionIdTest extends DataFileGeneratorTestSupport { + + + public static final SessionIdTest SINGLETON = new SessionIdTest(); + + public Object createObject() throws Exception { + SessionId info = new SessionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionId info = (SessionId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SessionInfoTest.java new file mode 100644 index 0000000000..81bed8bcfb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SessionInfoTest.java @@ -0,0 +1,50 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.SessionInfo; + + +/** + * Test case for the OpenWire marshalling for SessionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionInfoTest extends BaseCommandTestSupport { + + + public static final SessionInfoTest SINGLETON = new SessionInfoTest(); + + public Object createObject() throws Exception { + SessionInfo info = new SessionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionInfo info = (SessionInfo) object; + + info.setSessionId(createSessionId("SessionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ShutdownInfoTest.java new file mode 100644 index 0000000000..2c8c03fb99 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/ShutdownInfoTest.java @@ -0,0 +1,49 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.ShutdownInfo; + + +/** + * Test case for the OpenWire marshalling for ShutdownInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ShutdownInfoTest extends BaseCommandTestSupport { + + + public static final ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); + + public Object createObject() throws Exception { + ShutdownInfo info = new ShutdownInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ShutdownInfo info = (ShutdownInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SubscriptionInfoTest.java new file mode 100644 index 0000000000..d8da085a71 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/SubscriptionInfoTest.java @@ -0,0 +1,55 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.SubscriptionInfo; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for SubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { + + + public static final SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); + + public Object createObject() throws Exception { + SubscriptionInfo info = new SubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SubscriptionInfo info = (SubscriptionInfo) object; + + info.setClientId("ClientId:1"); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubcriptionName:4"); + info.setSubscribedDestination(createActiveMQDestination("SubscribedDestination:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/TransactionIdTestSupport.java new file mode 100644 index 0000000000..ce874bbe7e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/TransactionIdTestSupport.java @@ -0,0 +1,42 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + + +/** + * Test case for the OpenWire marshalling for TransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionId info = (TransactionId) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/TransactionInfoTest.java new file mode 100644 index 0000000000..8daad3904f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/TransactionInfoTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.TransactionInfo; + + +/** + * Test case for the OpenWire marshalling for TransactionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class TransactionInfoTest extends BaseCommandTestSupport { + + + public static final TransactionInfoTest SINGLETON = new TransactionInfoTest(); + + public Object createObject() throws Exception { + TransactionInfo info = new TransactionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionInfo info = (TransactionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setType((byte) 1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/XATransactionIdTest.java new file mode 100644 index 0000000000..e9d36e375b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v3/XATransactionIdTest.java @@ -0,0 +1,52 @@ +/** + * 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.openwire.v3; + +import org.apache.activemq.command.XATransactionId; + + +/** + * Test case for the OpenWire marshalling for XATransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class XATransactionIdTest extends TransactionIdTestSupport { + + + public static final XATransactionIdTest SINGLETON = new XATransactionIdTest(); + + public Object createObject() throws Exception { + XATransactionId info = new XATransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + XATransactionId info = (XATransactionId) object; + + info.setFormatId(1); + info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); + info.setBranchQualifier("BranchQualifier:2".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BaseCommandTestSupport.java new file mode 100644 index 0000000000..f281a94c1d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BaseCommandTestSupport.java @@ -0,0 +1,39 @@ +/** + * 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.openwire.v4; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BrokerIdTest.java new file mode 100644 index 0000000000..97cf0488b4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BrokerIdTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for BrokerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerIdTest extends DataFileGeneratorTestSupport { + + + public static BrokerIdTest SINGLETON = new BrokerIdTest(); + + public Object createObject() throws Exception { + BrokerId info = new BrokerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerId info = (BrokerId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BrokerInfoTest.java new file mode 100644 index 0000000000..b76df14501 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/BrokerInfoTest.java @@ -0,0 +1,73 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for BrokerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerInfoTest extends BaseCommandTestSupport { + + + public static BrokerInfoTest SINGLETON = new BrokerInfoTest(); + + public Object createObject() throws Exception { + BrokerInfo info = new BrokerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerInfo info = (BrokerInfo) object; + + info.setBrokerId(createBrokerId("BrokerId:1")); + info.setBrokerURL("BrokerURL:2"); + { + BrokerInfo value[] = new BrokerInfo[0]; + for( int i=0; i < 0; i++ ) { + value[i] = createBrokerInfo("PeerBrokerInfos:3"); + } + info.setPeerBrokerInfos(value); + } + info.setBrokerName("BrokerName:4"); + info.setSlaveBroker(true); + info.setMasterBroker(false); + info.setFaultTolerantConfiguration(true); + info.setDuplexConnection(false); + info.setNetworkConnection(true); + info.setConnectionId(1); + info.setBrokerUploadUrl("BrokerUploadUrl:5"); + info.setNetworkProperties("NetworkProperties:6"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionControlTest.java new file mode 100644 index 0000000000..7250787861 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionControlTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionControlTest extends BaseCommandTestSupport { + + + public static ConnectionControlTest SINGLETON = new ConnectionControlTest(); + + public Object createObject() throws Exception { + ConnectionControl info = new ConnectionControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionControl info = (ConnectionControl) object; + + info.setClose(true); + info.setExit(false); + info.setFaultTolerant(true); + info.setResume(false); + info.setSuspend(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionErrorTest.java new file mode 100644 index 0000000000..56d4c89f97 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionErrorTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionError + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionErrorTest extends BaseCommandTestSupport { + + + public static ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); + + public Object createObject() throws Exception { + ConnectionError info = new ConnectionError(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionError info = (ConnectionError) object; + + info.setException(createThrowable("Exception:1")); + info.setConnectionId(createConnectionId("ConnectionId:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionIdTest.java new file mode 100644 index 0000000000..9f25aa7321 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionIdTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionIdTest extends DataFileGeneratorTestSupport { + + + public static ConnectionIdTest SINGLETON = new ConnectionIdTest(); + + public Object createObject() throws Exception { + ConnectionId info = new ConnectionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionId info = (ConnectionId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionInfoTest.java new file mode 100644 index 0000000000..56512a6a34 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConnectionInfoTest.java @@ -0,0 +1,69 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionInfoTest extends BaseCommandTestSupport { + + + public static ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); + + public Object createObject() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionInfo info = (ConnectionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setClientId("ClientId:2"); + info.setPassword("Password:3"); + info.setUserName("UserName:4"); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setBrokerMasterConnector(true); + info.setManageable(false); + info.setClientMaster(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerControlTest.java new file mode 100644 index 0000000000..e82fdccae2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerControlTest.java @@ -0,0 +1,61 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerControlTest extends BaseCommandTestSupport { + + + public static ConsumerControlTest SINGLETON = new ConsumerControlTest(); + + public Object createObject() throws Exception { + ConsumerControl info = new ConsumerControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerControl info = (ConsumerControl) object; + + info.setClose(true); + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setPrefetch(1); + info.setFlush(false); + info.setStart(true); + info.setStop(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerIdTest.java new file mode 100644 index 0000000000..cd26cb756d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerIdTest extends DataFileGeneratorTestSupport { + + + public static ConsumerIdTest SINGLETON = new ConsumerIdTest(); + + public Object createObject() throws Exception { + ConsumerId info = new ConsumerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerId info = (ConsumerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setSessionId(1); + info.setValue(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerInfoTest.java new file mode 100644 index 0000000000..277cbf57a8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ConsumerInfoTest.java @@ -0,0 +1,85 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerInfoTest extends BaseCommandTestSupport { + + + public static ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); + + public Object createObject() throws Exception { + ConsumerInfo info = new ConsumerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerInfo info = (ConsumerInfo) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setBrowser(true); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setPrefetchSize(1); + info.setMaximumPendingMessageLimit(2); + info.setDispatchAsync(false); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubscriptionName:4"); + info.setNoLocal(true); + info.setExclusive(false); + info.setRetroactive(true); + info.setPriority((byte) 1); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); + info.setNetworkSubscription(false); + info.setOptimizedAcknowledge(true); + info.setNoRangeAcks(false); + { + ConsumerId value[] = new ConsumerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createConsumerId("NetworkConsumerPath:7"); + } + info.setNetworkConsumerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ControlCommandTest.java new file mode 100644 index 0000000000..850c663e67 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ControlCommandTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ControlCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ControlCommandTest extends BaseCommandTestSupport { + + + public static ControlCommandTest SINGLETON = new ControlCommandTest(); + + public Object createObject() throws Exception { + ControlCommand info = new ControlCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ControlCommand info = (ControlCommand) object; + + info.setCommand("Command:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DataArrayResponseTest.java new file mode 100644 index 0000000000..20fdd6baf1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DataArrayResponseTest.java @@ -0,0 +1,62 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DataArrayResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataArrayResponseTest extends ResponseTest { + + + public static DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); + + public Object createObject() throws Exception { + DataArrayResponse info = new DataArrayResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataArrayResponse info = (DataArrayResponse) object; + + { + DataStructure value[] = new DataStructure[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createDataStructure("Data:1"); + } + info.setData(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DataResponseTest.java new file mode 100644 index 0000000000..d7c4c3d8ea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DataResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DataResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataResponseTest extends ResponseTest { + + + public static DataResponseTest SINGLETON = new DataResponseTest(); + + public Object createObject() throws Exception { + DataResponse info = new DataResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataResponse info = (DataResponse) object; + + info.setData(createDataStructure("Data:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DestinationInfoTest.java new file mode 100644 index 0000000000..cb9fa0a019 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DestinationInfoTest.java @@ -0,0 +1,66 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DestinationInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DestinationInfoTest extends BaseCommandTestSupport { + + + public static DestinationInfoTest SINGLETON = new DestinationInfoTest(); + + public Object createObject() throws Exception { + DestinationInfo info = new DestinationInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DestinationInfo info = (DestinationInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setOperationType((byte) 1); + info.setTimeout(1); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DiscoveryEventTest.java new file mode 100644 index 0000000000..e8dbb59386 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/DiscoveryEventTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DiscoveryEvent + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DiscoveryEventTest extends DataFileGeneratorTestSupport { + + + public static DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); + + public Object createObject() throws Exception { + DiscoveryEvent info = new DiscoveryEvent(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DiscoveryEvent info = (DiscoveryEvent) object; + + info.setServiceName("ServiceName:1"); + info.setBrokerName("BrokerName:2"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ExceptionResponseTest.java new file mode 100644 index 0000000000..320b22cc57 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ExceptionResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ExceptionResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ExceptionResponseTest extends ResponseTest { + + + public static ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); + + public Object createObject() throws Exception { + ExceptionResponse info = new ExceptionResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ExceptionResponse info = (ExceptionResponse) object; + + info.setException(createThrowable("Exception:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/FlushCommandTest.java new file mode 100644 index 0000000000..330b6af1e9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/FlushCommandTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for FlushCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class FlushCommandTest extends BaseCommandTestSupport { + + + public static FlushCommandTest SINGLETON = new FlushCommandTest(); + + public Object createObject() throws Exception { + FlushCommand info = new FlushCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + FlushCommand info = (FlushCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/IntegerResponseTest.java new file mode 100644 index 0000000000..98c8e90d8c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/IntegerResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for IntegerResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class IntegerResponseTest extends ResponseTest { + + + public static IntegerResponseTest SINGLETON = new IntegerResponseTest(); + + public Object createObject() throws Exception { + IntegerResponse info = new IntegerResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + IntegerResponse info = (IntegerResponse) object; + + info.setResult(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalQueueAckTest.java new file mode 100644 index 0000000000..1d7cba69e1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalQueueAckTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalQueueAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalQueueAckTest extends DataFileGeneratorTestSupport { + + + public static JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); + + public Object createObject() throws Exception { + JournalQueueAck info = new JournalQueueAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalQueueAck info = (JournalQueueAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageAck(createMessageAck("MessageAck:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTopicAckTest.java new file mode 100644 index 0000000000..ece67794dc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTopicAckTest.java @@ -0,0 +1,61 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTopicAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTopicAckTest extends DataFileGeneratorTestSupport { + + + public static JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); + + public Object createObject() throws Exception { + JournalTopicAck info = new JournalTopicAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTopicAck info = (JournalTopicAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageId(createMessageId("MessageId:2")); + info.setMessageSequenceId(1); + info.setSubscritionName("SubscritionName:3"); + info.setClientId("ClientId:4"); + info.setTransactionId(createTransactionId("TransactionId:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTraceTest.java new file mode 100644 index 0000000000..125d9844ee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTraceTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTrace + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTraceTest extends DataFileGeneratorTestSupport { + + + public static JournalTraceTest SINGLETON = new JournalTraceTest(); + + public Object createObject() throws Exception { + JournalTrace info = new JournalTrace(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTrace info = (JournalTrace) object; + + info.setMessage("Message:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTransactionTest.java new file mode 100644 index 0000000000..3dc47ab73b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/JournalTransactionTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTransaction + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTransactionTest extends DataFileGeneratorTestSupport { + + + public static JournalTransactionTest SINGLETON = new JournalTransactionTest(); + + public Object createObject() throws Exception { + JournalTransaction info = new JournalTransaction(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTransaction info = (JournalTransaction) object; + + info.setTransactionId(createTransactionId("TransactionId:1")); + info.setType((byte) 1); + info.setWasPrepared(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/KeepAliveInfoTest.java new file mode 100644 index 0000000000..d804f5006f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/KeepAliveInfoTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for KeepAliveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class KeepAliveInfoTest extends BaseCommandTestSupport { + + + public static KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); + + public Object createObject() throws Exception { + KeepAliveInfo info = new KeepAliveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + KeepAliveInfo info = (KeepAliveInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/LastPartialCommandTest.java new file mode 100644 index 0000000000..81c1eb3101 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/LastPartialCommandTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for LastPartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LastPartialCommandTest extends PartialCommandTest { + + + public static LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); + + public Object createObject() throws Exception { + LastPartialCommand info = new LastPartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LastPartialCommand info = (LastPartialCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/LocalTransactionIdTest.java new file mode 100644 index 0000000000..544220b6dc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/LocalTransactionIdTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for LocalTransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LocalTransactionIdTest extends TransactionIdTestSupport { + + + public static LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); + + public Object createObject() throws Exception { + LocalTransactionId info = new LocalTransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LocalTransactionId info = (LocalTransactionId) object; + + info.setValue(1); + info.setConnectionId(createConnectionId("ConnectionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageAckTest.java new file mode 100644 index 0000000000..440bfdf092 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageAckTest.java @@ -0,0 +1,62 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageAckTest extends BaseCommandTestSupport { + + + public static MessageAckTest SINGLETON = new MessageAckTest(); + + public Object createObject() throws Exception { + MessageAck info = new MessageAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageAck info = (MessageAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setConsumerId(createConsumerId("ConsumerId:3")); + info.setAckType((byte) 1); + info.setFirstMessageId(createMessageId("FirstMessageId:4")); + info.setLastMessageId(createMessageId("LastMessageId:5")); + info.setMessageCount(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..bfa23002c1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageDispatchNotificationTest.java @@ -0,0 +1,59 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageDispatchNotification + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchNotificationTest extends BaseCommandTestSupport { + + + public static MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); + + public Object createObject() throws Exception { + MessageDispatchNotification info = new MessageDispatchNotification(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatchNotification info = (MessageDispatchNotification) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setDeliverySequenceId(1); + info.setMessageId(createMessageId("MessageId:3")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageDispatchTest.java new file mode 100644 index 0000000000..41e40f7982 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageDispatchTest.java @@ -0,0 +1,59 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageDispatch + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchTest extends BaseCommandTestSupport { + + + public static MessageDispatchTest SINGLETON = new MessageDispatchTest(); + + public Object createObject() throws Exception { + MessageDispatch info = new MessageDispatch(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatch info = (MessageDispatch) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setMessage(createMessage("Message:3")); + info.setRedeliveryCounter(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageIdTest.java new file mode 100644 index 0000000000..fcdc62f728 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageIdTest extends DataFileGeneratorTestSupport { + + + public static MessageIdTest SINGLETON = new MessageIdTest(); + + public Object createObject() throws Exception { + MessageId info = new MessageId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageId info = (MessageId) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setProducerSequenceId(1); + info.setBrokerSequenceId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessagePullTest.java new file mode 100644 index 0000000000..f07f82774f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessagePullTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessagePull + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessagePullTest extends BaseCommandTestSupport { + + + public static MessagePullTest SINGLETON = new MessagePullTest(); + + public Object createObject() throws Exception { + MessagePull info = new MessagePull(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessagePull info = (MessagePull) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTimeout(1); + info.setCorrelationId("CorrelationId:3"); + info.setMessageId(createMessageId("MessageId:4")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageTestSupport.java new file mode 100644 index 0000000000..f45b80c7d4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/MessageTestSupport.java @@ -0,0 +1,89 @@ +/** + * + * 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.openwire.v4; + +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for Message + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class MessageTestSupport extends BaseCommandTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Message info = (Message) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTransactionId(createTransactionId("TransactionId:3")); + info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); + info.setMessageId(createMessageId("MessageId:5")); + info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); + info.setGroupID("GroupID:7"); + info.setGroupSequence(1); + info.setCorrelationId("CorrelationId:8"); + info.setPersistent(true); + info.setExpiration(1); + info.setPriority((byte) 1); + info.setReplyTo(createActiveMQDestination("ReplyTo:9")); + info.setTimestamp(2); + info.setType("Type:10"); + { + byte data[] = "Content:11".getBytes(); + info.setContent(new org.apache.activemq.util.ByteSequence(data,0,data.length)); +} + { + byte data[] = "MarshalledProperties:12".getBytes(); + info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data,0,data.length)); +} + info.setDataStructure(createDataStructure("DataStructure:13")); + info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); + info.setCompressed(false); + info.setRedeliveryCounter(2); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:15"); + } + info.setBrokerPath(value); + } + info.setArrival(3); + info.setUserID("UserID:16"); + info.setRecievedByDFBridge(true); + info.setDroppable(false); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("Cluster:17"); + } + info.setCluster(value); + } + info.setBrokerInTime(4); + info.setBrokerOutTime(5); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..e07dc530eb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/NetworkBridgeFilterTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for NetworkBridgeFilter + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { + + + public static NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); + + public Object createObject() throws Exception { + NetworkBridgeFilter info = new NetworkBridgeFilter(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + NetworkBridgeFilter info = (NetworkBridgeFilter) object; + + info.setNetworkTTL(1); + info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/PartialCommandTest.java new file mode 100644 index 0000000000..a6e1f4790d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/PartialCommandTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for PartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class PartialCommandTest extends DataFileGeneratorTestSupport { + + + public static PartialCommandTest SINGLETON = new PartialCommandTest(); + + public Object createObject() throws Exception { + PartialCommand info = new PartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + PartialCommand info = (PartialCommand) object; + + info.setCommandId(1); + info.setData("Data:1".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerAckTest.java new file mode 100644 index 0000000000..c2de9581c0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerAckTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerAckTest extends BaseCommandTestSupport { + + + public static ProducerAckTest SINGLETON = new ProducerAckTest(); + + public Object createObject() throws Exception { + ProducerAck info = new ProducerAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerAck info = (ProducerAck) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerIdTest.java new file mode 100644 index 0000000000..a75953df78 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerIdTest extends DataFileGeneratorTestSupport { + + + public static ProducerIdTest SINGLETON = new ProducerIdTest(); + + public Object createObject() throws Exception { + ProducerId info = new ProducerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerId info = (ProducerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + info.setSessionId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerInfoTest.java new file mode 100644 index 0000000000..d6bafb6e44 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ProducerInfoTest.java @@ -0,0 +1,66 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerInfoTest extends BaseCommandTestSupport { + + + public static ProducerInfoTest SINGLETON = new ProducerInfoTest(); + + public Object createObject() throws Exception { + ProducerInfo info = new ProducerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerInfo info = (ProducerInfo) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + info.setDispatchAsync(true); + info.setWindowSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/RemoveInfoTest.java new file mode 100644 index 0000000000..45f05a3e16 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/RemoveInfoTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for RemoveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveInfoTest extends BaseCommandTestSupport { + + + public static RemoveInfoTest SINGLETON = new RemoveInfoTest(); + + public Object createObject() throws Exception { + RemoveInfo info = new RemoveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveInfo info = (RemoveInfo) object; + + info.setObjectId(createDataStructure("ObjectId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..f2e0fd0953 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/RemoveSubscriptionInfoTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for RemoveSubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { + + + public static RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); + + public Object createObject() throws Exception { + RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setSubscriptionName("SubcriptionName:2"); + info.setClientId("ClientId:3"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ReplayCommandTest.java new file mode 100644 index 0000000000..81028a7290 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ReplayCommandTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ReplayCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ReplayCommandTest extends BaseCommandTestSupport { + + + public static ReplayCommandTest SINGLETON = new ReplayCommandTest(); + + public Object createObject() throws Exception { + ReplayCommand info = new ReplayCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ReplayCommand info = (ReplayCommand) object; + + info.setFirstNakNumber(1); + info.setLastNakNumber(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ResponseTest.java new file mode 100644 index 0000000000..f757031c4f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for Response + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ResponseTest extends BaseCommandTestSupport { + + + public static ResponseTest SINGLETON = new ResponseTest(); + + public Object createObject() throws Exception { + Response info = new Response(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Response info = (Response) object; + + info.setCorrelationId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SessionIdTest.java new file mode 100644 index 0000000000..923f49b0b5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SessionIdTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SessionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionIdTest extends DataFileGeneratorTestSupport { + + + public static SessionIdTest SINGLETON = new SessionIdTest(); + + public Object createObject() throws Exception { + SessionId info = new SessionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionId info = (SessionId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SessionInfoTest.java new file mode 100644 index 0000000000..ed897c64c4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SessionInfoTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SessionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionInfoTest extends BaseCommandTestSupport { + + + public static SessionInfoTest SINGLETON = new SessionInfoTest(); + + public Object createObject() throws Exception { + SessionInfo info = new SessionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionInfo info = (SessionInfo) object; + + info.setSessionId(createSessionId("SessionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ShutdownInfoTest.java new file mode 100644 index 0000000000..411d392720 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/ShutdownInfoTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ShutdownInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ShutdownInfoTest extends BaseCommandTestSupport { + + + public static ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); + + public Object createObject() throws Exception { + ShutdownInfo info = new ShutdownInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ShutdownInfo info = (ShutdownInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SubscriptionInfoTest.java new file mode 100644 index 0000000000..1724bee351 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/SubscriptionInfoTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { + + + public static SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); + + public Object createObject() throws Exception { + SubscriptionInfo info = new SubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SubscriptionInfo info = (SubscriptionInfo) object; + + info.setClientId("ClientId:1"); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubcriptionName:4"); + info.setSubscribedDestination(createActiveMQDestination("SubscribedDestination:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/TransactionIdTestSupport.java new file mode 100644 index 0000000000..6172e4d942 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/TransactionIdTestSupport.java @@ -0,0 +1,47 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for TransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionId info = (TransactionId) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/TransactionInfoTest.java new file mode 100644 index 0000000000..26e2f41b2f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/TransactionInfoTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for TransactionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class TransactionInfoTest extends BaseCommandTestSupport { + + + public static TransactionInfoTest SINGLETON = new TransactionInfoTest(); + + public Object createObject() throws Exception { + TransactionInfo info = new TransactionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionInfo info = (TransactionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setType((byte) 1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/XATransactionIdTest.java new file mode 100644 index 0000000000..d79de31ff5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v4/XATransactionIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v4; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for XATransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class XATransactionIdTest extends TransactionIdTestSupport { + + + public static XATransactionIdTest SINGLETON = new XATransactionIdTest(); + + public Object createObject() throws Exception { + XATransactionId info = new XATransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + XATransactionId info = (XATransactionId) object; + + info.setFormatId(1); + info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); + info.setBranchQualifier("BranchQualifier:2".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BaseCommandTestSupport.java new file mode 100644 index 0000000000..55bfd64f78 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BaseCommandTestSupport.java @@ -0,0 +1,38 @@ +/** + * 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.openwire.v5; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BrokerIdTest.java new file mode 100644 index 0000000000..d5ebc11b01 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BrokerIdTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for BrokerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerIdTest extends DataFileGeneratorTestSupport { + + + public static BrokerIdTest SINGLETON = new BrokerIdTest(); + + public Object createObject() throws Exception { + BrokerId info = new BrokerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerId info = (BrokerId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BrokerInfoTest.java new file mode 100644 index 0000000000..26186f17e2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/BrokerInfoTest.java @@ -0,0 +1,73 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for BrokerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerInfoTest extends BaseCommandTestSupport { + + + public static BrokerInfoTest SINGLETON = new BrokerInfoTest(); + + public Object createObject() throws Exception { + BrokerInfo info = new BrokerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerInfo info = (BrokerInfo) object; + + info.setBrokerId(createBrokerId("BrokerId:1")); + info.setBrokerURL("BrokerURL:2"); + { + BrokerInfo value[] = new BrokerInfo[0]; + for( int i=0; i < 0; i++ ) { + value[i] = createBrokerInfo("PeerBrokerInfos:3"); + } + info.setPeerBrokerInfos(value); + } + info.setBrokerName("BrokerName:4"); + info.setSlaveBroker(true); + info.setMasterBroker(false); + info.setFaultTolerantConfiguration(true); + info.setDuplexConnection(false); + info.setNetworkConnection(true); + info.setConnectionId(1); + info.setBrokerUploadUrl("BrokerUploadUrl:5"); + info.setNetworkProperties("NetworkProperties:6"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionControlTest.java new file mode 100644 index 0000000000..fa2e0cc082 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionControlTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionControlTest extends BaseCommandTestSupport { + + + public static ConnectionControlTest SINGLETON = new ConnectionControlTest(); + + public Object createObject() throws Exception { + ConnectionControl info = new ConnectionControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionControl info = (ConnectionControl) object; + + info.setClose(true); + info.setExit(false); + info.setFaultTolerant(true); + info.setResume(false); + info.setSuspend(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionErrorTest.java new file mode 100644 index 0000000000..52420e2147 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionErrorTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionError + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionErrorTest extends BaseCommandTestSupport { + + + public static ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); + + public Object createObject() throws Exception { + ConnectionError info = new ConnectionError(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionError info = (ConnectionError) object; + + info.setException(createThrowable("Exception:1")); + info.setConnectionId(createConnectionId("ConnectionId:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionIdTest.java new file mode 100644 index 0000000000..e69d674174 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionIdTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionIdTest extends DataFileGeneratorTestSupport { + + + public static ConnectionIdTest SINGLETON = new ConnectionIdTest(); + + public Object createObject() throws Exception { + ConnectionId info = new ConnectionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionId info = (ConnectionId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionInfoTest.java new file mode 100644 index 0000000000..776b2d2029 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConnectionInfoTest.java @@ -0,0 +1,69 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionInfoTest extends BaseCommandTestSupport { + + + public static ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); + + public Object createObject() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionInfo info = (ConnectionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setClientId("ClientId:2"); + info.setPassword("Password:3"); + info.setUserName("UserName:4"); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setBrokerMasterConnector(true); + info.setManageable(false); + info.setClientMaster(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerControlTest.java new file mode 100644 index 0000000000..546f3cb4f5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerControlTest.java @@ -0,0 +1,61 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerControlTest extends BaseCommandTestSupport { + + + public static ConsumerControlTest SINGLETON = new ConsumerControlTest(); + + public Object createObject() throws Exception { + ConsumerControl info = new ConsumerControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerControl info = (ConsumerControl) object; + + info.setClose(true); + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setPrefetch(1); + info.setFlush(false); + info.setStart(true); + info.setStop(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerIdTest.java new file mode 100644 index 0000000000..cfcac6a707 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerIdTest extends DataFileGeneratorTestSupport { + + + public static ConsumerIdTest SINGLETON = new ConsumerIdTest(); + + public Object createObject() throws Exception { + ConsumerId info = new ConsumerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerId info = (ConsumerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setSessionId(1); + info.setValue(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerInfoTest.java new file mode 100644 index 0000000000..3316d2083a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ConsumerInfoTest.java @@ -0,0 +1,85 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerInfoTest extends BaseCommandTestSupport { + + + public static ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); + + public Object createObject() throws Exception { + ConsumerInfo info = new ConsumerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerInfo info = (ConsumerInfo) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setBrowser(true); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setPrefetchSize(1); + info.setMaximumPendingMessageLimit(2); + info.setDispatchAsync(false); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubscriptionName:4"); + info.setNoLocal(true); + info.setExclusive(false); + info.setRetroactive(true); + info.setPriority((byte) 1); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); + info.setNetworkSubscription(false); + info.setOptimizedAcknowledge(true); + info.setNoRangeAcks(false); + { + ConsumerId value[] = new ConsumerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createConsumerId("NetworkConsumerPath:7"); + } + info.setNetworkConsumerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ControlCommandTest.java new file mode 100644 index 0000000000..04c41d3ee5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ControlCommandTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ControlCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ControlCommandTest extends BaseCommandTestSupport { + + + public static ControlCommandTest SINGLETON = new ControlCommandTest(); + + public Object createObject() throws Exception { + ControlCommand info = new ControlCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ControlCommand info = (ControlCommand) object; + + info.setCommand("Command:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DataArrayResponseTest.java new file mode 100644 index 0000000000..52d2dfd277 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DataArrayResponseTest.java @@ -0,0 +1,62 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DataArrayResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataArrayResponseTest extends ResponseTest { + + + public static DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); + + public Object createObject() throws Exception { + DataArrayResponse info = new DataArrayResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataArrayResponse info = (DataArrayResponse) object; + + { + DataStructure value[] = new DataStructure[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createDataStructure("Data:1"); + } + info.setData(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DataResponseTest.java new file mode 100644 index 0000000000..d1047de6ac --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DataResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DataResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataResponseTest extends ResponseTest { + + + public static DataResponseTest SINGLETON = new DataResponseTest(); + + public Object createObject() throws Exception { + DataResponse info = new DataResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataResponse info = (DataResponse) object; + + info.setData(createDataStructure("Data:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DestinationInfoTest.java new file mode 100644 index 0000000000..45ef248c9b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DestinationInfoTest.java @@ -0,0 +1,66 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DestinationInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DestinationInfoTest extends BaseCommandTestSupport { + + + public static DestinationInfoTest SINGLETON = new DestinationInfoTest(); + + public Object createObject() throws Exception { + DestinationInfo info = new DestinationInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DestinationInfo info = (DestinationInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setOperationType((byte) 1); + info.setTimeout(1); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DiscoveryEventTest.java new file mode 100644 index 0000000000..2c2cbabbce --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/DiscoveryEventTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DiscoveryEvent + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DiscoveryEventTest extends DataFileGeneratorTestSupport { + + + public static DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); + + public Object createObject() throws Exception { + DiscoveryEvent info = new DiscoveryEvent(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DiscoveryEvent info = (DiscoveryEvent) object; + + info.setServiceName("ServiceName:1"); + info.setBrokerName("BrokerName:2"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ExceptionResponseTest.java new file mode 100644 index 0000000000..41d60e2d5b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ExceptionResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ExceptionResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ExceptionResponseTest extends ResponseTest { + + + public static ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); + + public Object createObject() throws Exception { + ExceptionResponse info = new ExceptionResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ExceptionResponse info = (ExceptionResponse) object; + + info.setException(createThrowable("Exception:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/FlushCommandTest.java new file mode 100644 index 0000000000..c48a679b26 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/FlushCommandTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for FlushCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class FlushCommandTest extends BaseCommandTestSupport { + + + public static FlushCommandTest SINGLETON = new FlushCommandTest(); + + public Object createObject() throws Exception { + FlushCommand info = new FlushCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + FlushCommand info = (FlushCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/IntegerResponseTest.java new file mode 100644 index 0000000000..7737769289 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/IntegerResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for IntegerResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class IntegerResponseTest extends ResponseTest { + + + public static IntegerResponseTest SINGLETON = new IntegerResponseTest(); + + public Object createObject() throws Exception { + IntegerResponse info = new IntegerResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + IntegerResponse info = (IntegerResponse) object; + + info.setResult(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalQueueAckTest.java new file mode 100644 index 0000000000..0f1de7eb81 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalQueueAckTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalQueueAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalQueueAckTest extends DataFileGeneratorTestSupport { + + + public static JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); + + public Object createObject() throws Exception { + JournalQueueAck info = new JournalQueueAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalQueueAck info = (JournalQueueAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageAck(createMessageAck("MessageAck:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTopicAckTest.java new file mode 100644 index 0000000000..d0856f8ef5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTopicAckTest.java @@ -0,0 +1,61 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTopicAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTopicAckTest extends DataFileGeneratorTestSupport { + + + public static JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); + + public Object createObject() throws Exception { + JournalTopicAck info = new JournalTopicAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTopicAck info = (JournalTopicAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageId(createMessageId("MessageId:2")); + info.setMessageSequenceId(1); + info.setSubscritionName("SubscritionName:3"); + info.setClientId("ClientId:4"); + info.setTransactionId(createTransactionId("TransactionId:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTraceTest.java new file mode 100644 index 0000000000..530f2ad945 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTraceTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTrace + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTraceTest extends DataFileGeneratorTestSupport { + + + public static JournalTraceTest SINGLETON = new JournalTraceTest(); + + public Object createObject() throws Exception { + JournalTrace info = new JournalTrace(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTrace info = (JournalTrace) object; + + info.setMessage("Message:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTransactionTest.java new file mode 100644 index 0000000000..4348e23a4b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/JournalTransactionTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTransaction + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTransactionTest extends DataFileGeneratorTestSupport { + + + public static JournalTransactionTest SINGLETON = new JournalTransactionTest(); + + public Object createObject() throws Exception { + JournalTransaction info = new JournalTransaction(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTransaction info = (JournalTransaction) object; + + info.setTransactionId(createTransactionId("TransactionId:1")); + info.setType((byte) 1); + info.setWasPrepared(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/KeepAliveInfoTest.java new file mode 100644 index 0000000000..48610fa4a6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/KeepAliveInfoTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for KeepAliveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class KeepAliveInfoTest extends BaseCommandTestSupport { + + + public static KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); + + public Object createObject() throws Exception { + KeepAliveInfo info = new KeepAliveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + KeepAliveInfo info = (KeepAliveInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/LastPartialCommandTest.java new file mode 100644 index 0000000000..edef39aea5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/LastPartialCommandTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for LastPartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LastPartialCommandTest extends PartialCommandTest { + + + public static LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); + + public Object createObject() throws Exception { + LastPartialCommand info = new LastPartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LastPartialCommand info = (LastPartialCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/LocalTransactionIdTest.java new file mode 100644 index 0000000000..ba1f7c8752 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/LocalTransactionIdTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for LocalTransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LocalTransactionIdTest extends TransactionIdTestSupport { + + + public static LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); + + public Object createObject() throws Exception { + LocalTransactionId info = new LocalTransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LocalTransactionId info = (LocalTransactionId) object; + + info.setValue(1); + info.setConnectionId(createConnectionId("ConnectionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageAckTest.java new file mode 100644 index 0000000000..3185c7945b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageAckTest.java @@ -0,0 +1,62 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageAckTest extends BaseCommandTestSupport { + + + public static MessageAckTest SINGLETON = new MessageAckTest(); + + public Object createObject() throws Exception { + MessageAck info = new MessageAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageAck info = (MessageAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setConsumerId(createConsumerId("ConsumerId:3")); + info.setAckType((byte) 1); + info.setFirstMessageId(createMessageId("FirstMessageId:4")); + info.setLastMessageId(createMessageId("LastMessageId:5")); + info.setMessageCount(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..296aba735b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageDispatchNotificationTest.java @@ -0,0 +1,59 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageDispatchNotification + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchNotificationTest extends BaseCommandTestSupport { + + + public static MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); + + public Object createObject() throws Exception { + MessageDispatchNotification info = new MessageDispatchNotification(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatchNotification info = (MessageDispatchNotification) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setDeliverySequenceId(1); + info.setMessageId(createMessageId("MessageId:3")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageDispatchTest.java new file mode 100644 index 0000000000..a8c69871f2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageDispatchTest.java @@ -0,0 +1,59 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageDispatch + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchTest extends BaseCommandTestSupport { + + + public static MessageDispatchTest SINGLETON = new MessageDispatchTest(); + + public Object createObject() throws Exception { + MessageDispatch info = new MessageDispatch(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatch info = (MessageDispatch) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setMessage(createMessage("Message:3")); + info.setRedeliveryCounter(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageIdTest.java new file mode 100644 index 0000000000..78e8029bf0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageIdTest extends DataFileGeneratorTestSupport { + + + public static MessageIdTest SINGLETON = new MessageIdTest(); + + public Object createObject() throws Exception { + MessageId info = new MessageId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageId info = (MessageId) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setProducerSequenceId(1); + info.setBrokerSequenceId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessagePullTest.java new file mode 100644 index 0000000000..f23fa67b1f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessagePullTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessagePull + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessagePullTest extends BaseCommandTestSupport { + + + public static MessagePullTest SINGLETON = new MessagePullTest(); + + public Object createObject() throws Exception { + MessagePull info = new MessagePull(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessagePull info = (MessagePull) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTimeout(1); + info.setCorrelationId("CorrelationId:3"); + info.setMessageId(createMessageId("MessageId:4")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageTestSupport.java new file mode 100644 index 0000000000..e5bfe05728 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/MessageTestSupport.java @@ -0,0 +1,89 @@ +/** + * + * 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.openwire.v5; + +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for Message + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class MessageTestSupport extends BaseCommandTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Message info = (Message) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTransactionId(createTransactionId("TransactionId:3")); + info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); + info.setMessageId(createMessageId("MessageId:5")); + info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); + info.setGroupID("GroupID:7"); + info.setGroupSequence(1); + info.setCorrelationId("CorrelationId:8"); + info.setPersistent(true); + info.setExpiration(1); + info.setPriority((byte) 1); + info.setReplyTo(createActiveMQDestination("ReplyTo:9")); + info.setTimestamp(2); + info.setType("Type:10"); + { + byte data[] = "Content:11".getBytes(); + info.setContent(new org.apache.activemq.util.ByteSequence(data,0,data.length)); +} + { + byte data[] = "MarshalledProperties:12".getBytes(); + info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data,0,data.length)); +} + info.setDataStructure(createDataStructure("DataStructure:13")); + info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); + info.setCompressed(false); + info.setRedeliveryCounter(2); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:15"); + } + info.setBrokerPath(value); + } + info.setArrival(3); + info.setUserID("UserID:16"); + info.setRecievedByDFBridge(true); + info.setDroppable(false); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("Cluster:17"); + } + info.setCluster(value); + } + info.setBrokerInTime(4); + info.setBrokerOutTime(5); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..e2e8fef56b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/NetworkBridgeFilterTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for NetworkBridgeFilter + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { + + + public static NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); + + public Object createObject() throws Exception { + NetworkBridgeFilter info = new NetworkBridgeFilter(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + NetworkBridgeFilter info = (NetworkBridgeFilter) object; + + info.setNetworkTTL(1); + info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/PartialCommandTest.java new file mode 100644 index 0000000000..c234eaf1f3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/PartialCommandTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for PartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class PartialCommandTest extends DataFileGeneratorTestSupport { + + + public static PartialCommandTest SINGLETON = new PartialCommandTest(); + + public Object createObject() throws Exception { + PartialCommand info = new PartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + PartialCommand info = (PartialCommand) object; + + info.setCommandId(1); + info.setData("Data:1".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerAckTest.java new file mode 100644 index 0000000000..48fd0c7ff3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerAckTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerAckTest extends BaseCommandTestSupport { + + + public static ProducerAckTest SINGLETON = new ProducerAckTest(); + + public Object createObject() throws Exception { + ProducerAck info = new ProducerAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerAck info = (ProducerAck) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerIdTest.java new file mode 100644 index 0000000000..e4994ff06f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerIdTest extends DataFileGeneratorTestSupport { + + + public static ProducerIdTest SINGLETON = new ProducerIdTest(); + + public Object createObject() throws Exception { + ProducerId info = new ProducerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerId info = (ProducerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + info.setSessionId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerInfoTest.java new file mode 100644 index 0000000000..1dc0633083 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ProducerInfoTest.java @@ -0,0 +1,66 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerInfoTest extends BaseCommandTestSupport { + + + public static ProducerInfoTest SINGLETON = new ProducerInfoTest(); + + public Object createObject() throws Exception { + ProducerInfo info = new ProducerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerInfo info = (ProducerInfo) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + info.setDispatchAsync(true); + info.setWindowSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/RemoveInfoTest.java new file mode 100644 index 0000000000..e083079adf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/RemoveInfoTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for RemoveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveInfoTest extends BaseCommandTestSupport { + + + public static RemoveInfoTest SINGLETON = new RemoveInfoTest(); + + public Object createObject() throws Exception { + RemoveInfo info = new RemoveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveInfo info = (RemoveInfo) object; + + info.setObjectId(createDataStructure("ObjectId:1")); + info.setLastDeliveredSequenceId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..8c6c05698e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/RemoveSubscriptionInfoTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for RemoveSubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { + + + public static RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); + + public Object createObject() throws Exception { + RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setSubscriptionName("SubcriptionName:2"); + info.setClientId("ClientId:3"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ReplayCommandTest.java new file mode 100644 index 0000000000..c4a8879f93 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ReplayCommandTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ReplayCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ReplayCommandTest extends BaseCommandTestSupport { + + + public static ReplayCommandTest SINGLETON = new ReplayCommandTest(); + + public Object createObject() throws Exception { + ReplayCommand info = new ReplayCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ReplayCommand info = (ReplayCommand) object; + + info.setFirstNakNumber(1); + info.setLastNakNumber(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ResponseTest.java new file mode 100644 index 0000000000..4732749ba4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for Response + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ResponseTest extends BaseCommandTestSupport { + + + public static ResponseTest SINGLETON = new ResponseTest(); + + public Object createObject() throws Exception { + Response info = new Response(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Response info = (Response) object; + + info.setCorrelationId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SessionIdTest.java new file mode 100644 index 0000000000..c38b446420 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SessionIdTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SessionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionIdTest extends DataFileGeneratorTestSupport { + + + public static SessionIdTest SINGLETON = new SessionIdTest(); + + public Object createObject() throws Exception { + SessionId info = new SessionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionId info = (SessionId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SessionInfoTest.java new file mode 100644 index 0000000000..852a0d77b4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SessionInfoTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SessionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionInfoTest extends BaseCommandTestSupport { + + + public static SessionInfoTest SINGLETON = new SessionInfoTest(); + + public Object createObject() throws Exception { + SessionInfo info = new SessionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionInfo info = (SessionInfo) object; + + info.setSessionId(createSessionId("SessionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ShutdownInfoTest.java new file mode 100644 index 0000000000..af6e21a79b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/ShutdownInfoTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ShutdownInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ShutdownInfoTest extends BaseCommandTestSupport { + + + public static ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); + + public Object createObject() throws Exception { + ShutdownInfo info = new ShutdownInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ShutdownInfo info = (ShutdownInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SubscriptionInfoTest.java new file mode 100644 index 0000000000..5740f3e6f4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/SubscriptionInfoTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { + + + public static SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); + + public Object createObject() throws Exception { + SubscriptionInfo info = new SubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SubscriptionInfo info = (SubscriptionInfo) object; + + info.setClientId("ClientId:1"); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubcriptionName:4"); + info.setSubscribedDestination(createActiveMQDestination("SubscribedDestination:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/TransactionIdTestSupport.java new file mode 100644 index 0000000000..25c5f5a43f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/TransactionIdTestSupport.java @@ -0,0 +1,47 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for TransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionId info = (TransactionId) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/TransactionInfoTest.java new file mode 100644 index 0000000000..ab4a153572 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/TransactionInfoTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for TransactionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class TransactionInfoTest extends BaseCommandTestSupport { + + + public static TransactionInfoTest SINGLETON = new TransactionInfoTest(); + + public Object createObject() throws Exception { + TransactionInfo info = new TransactionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionInfo info = (TransactionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setType((byte) 1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/XATransactionIdTest.java new file mode 100644 index 0000000000..742a8bdcc3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v5/XATransactionIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v5; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for XATransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class XATransactionIdTest extends TransactionIdTestSupport { + + + public static XATransactionIdTest SINGLETON = new XATransactionIdTest(); + + public Object createObject() throws Exception { + XATransactionId info = new XATransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + XATransactionId info = (XATransactionId) object; + + info.setFormatId(1); + info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); + info.setBranchQualifier("BranchQualifier:2".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BaseCommandTestSupport.java new file mode 100644 index 0000000000..8c16b553e5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BaseCommandTestSupport.java @@ -0,0 +1,38 @@ +/** + * 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.openwire.v6; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BrokerIdTest.java new file mode 100644 index 0000000000..0f5ed87301 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BrokerIdTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for BrokerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerIdTest extends DataFileGeneratorTestSupport { + + + public static BrokerIdTest SINGLETON = new BrokerIdTest(); + + public Object createObject() throws Exception { + BrokerId info = new BrokerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerId info = (BrokerId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BrokerInfoTest.java new file mode 100644 index 0000000000..8c7f26d13f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/BrokerInfoTest.java @@ -0,0 +1,73 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for BrokerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class BrokerInfoTest extends BaseCommandTestSupport { + + + public static BrokerInfoTest SINGLETON = new BrokerInfoTest(); + + public Object createObject() throws Exception { + BrokerInfo info = new BrokerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BrokerInfo info = (BrokerInfo) object; + + info.setBrokerId(createBrokerId("BrokerId:1")); + info.setBrokerURL("BrokerURL:2"); + { + BrokerInfo value[] = new BrokerInfo[0]; + for( int i=0; i < 0; i++ ) { + value[i] = createBrokerInfo("PeerBrokerInfos:3"); + } + info.setPeerBrokerInfos(value); + } + info.setBrokerName("BrokerName:4"); + info.setSlaveBroker(true); + info.setMasterBroker(false); + info.setFaultTolerantConfiguration(true); + info.setDuplexConnection(false); + info.setNetworkConnection(true); + info.setConnectionId(1); + info.setBrokerUploadUrl("BrokerUploadUrl:5"); + info.setNetworkProperties("NetworkProperties:6"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionControlTest.java new file mode 100644 index 0000000000..f5aa0ca476 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionControlTest.java @@ -0,0 +1,63 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionControlTest extends BaseCommandTestSupport { + + + public static ConnectionControlTest SINGLETON = new ConnectionControlTest(); + + public Object createObject() throws Exception { + ConnectionControl info = new ConnectionControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionControl info = (ConnectionControl) object; + + info.setClose(true); + info.setExit(false); + info.setFaultTolerant(true); + info.setResume(false); + info.setSuspend(true); + info.setConnectedBrokers("ConnectedBrokers:1"); + info.setReconnectTo("ReconnectTo:2"); + info.setRebalanceConnection(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionErrorTest.java new file mode 100644 index 0000000000..156ff9f3fb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionErrorTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionError + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionErrorTest extends BaseCommandTestSupport { + + + public static ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); + + public Object createObject() throws Exception { + ConnectionError info = new ConnectionError(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionError info = (ConnectionError) object; + + info.setException(createThrowable("Exception:1")); + info.setConnectionId(createConnectionId("ConnectionId:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionIdTest.java new file mode 100644 index 0000000000..8fa7559a9e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionIdTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionIdTest extends DataFileGeneratorTestSupport { + + + public static ConnectionIdTest SINGLETON = new ConnectionIdTest(); + + public Object createObject() throws Exception { + ConnectionId info = new ConnectionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionId info = (ConnectionId) object; + + info.setValue("Value:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionInfoTest.java new file mode 100644 index 0000000000..fb3ecdb8ed --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConnectionInfoTest.java @@ -0,0 +1,71 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConnectionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConnectionInfoTest extends BaseCommandTestSupport { + + + public static ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); + + public Object createObject() throws Exception { + ConnectionInfo info = new ConnectionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConnectionInfo info = (ConnectionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setClientId("ClientId:2"); + info.setPassword("Password:3"); + info.setUserName("UserName:4"); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setBrokerMasterConnector(true); + info.setManageable(false); + info.setClientMaster(true); + info.setFaultTolerant(false); + info.setFailoverReconnect(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerControlTest.java new file mode 100644 index 0000000000..275ce11719 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerControlTest.java @@ -0,0 +1,62 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerControl + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerControlTest extends BaseCommandTestSupport { + + + public static ConsumerControlTest SINGLETON = new ConsumerControlTest(); + + public Object createObject() throws Exception { + ConsumerControl info = new ConsumerControl(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerControl info = (ConsumerControl) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setClose(true); + info.setConsumerId(createConsumerId("ConsumerId:2")); + info.setPrefetch(1); + info.setFlush(false); + info.setStart(true); + info.setStop(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerIdTest.java new file mode 100644 index 0000000000..d322dfbfce --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerIdTest extends DataFileGeneratorTestSupport { + + + public static ConsumerIdTest SINGLETON = new ConsumerIdTest(); + + public Object createObject() throws Exception { + ConsumerId info = new ConsumerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerId info = (ConsumerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setSessionId(1); + info.setValue(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerInfoTest.java new file mode 100644 index 0000000000..d8d1d0c403 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ConsumerInfoTest.java @@ -0,0 +1,85 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ConsumerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ConsumerInfoTest extends BaseCommandTestSupport { + + + public static ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); + + public Object createObject() throws Exception { + ConsumerInfo info = new ConsumerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ConsumerInfo info = (ConsumerInfo) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setBrowser(true); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setPrefetchSize(1); + info.setMaximumPendingMessageLimit(2); + info.setDispatchAsync(false); + info.setSelector("Selector:3"); + info.setSubscriptionName("SubscriptionName:4"); + info.setNoLocal(true); + info.setExclusive(false); + info.setRetroactive(true); + info.setPriority((byte) 1); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:5"); + } + info.setBrokerPath(value); + } + info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); + info.setNetworkSubscription(false); + info.setOptimizedAcknowledge(true); + info.setNoRangeAcks(false); + { + ConsumerId value[] = new ConsumerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createConsumerId("NetworkConsumerPath:7"); + } + info.setNetworkConsumerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ControlCommandTest.java new file mode 100644 index 0000000000..8b48365186 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ControlCommandTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ControlCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ControlCommandTest extends BaseCommandTestSupport { + + + public static ControlCommandTest SINGLETON = new ControlCommandTest(); + + public Object createObject() throws Exception { + ControlCommand info = new ControlCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ControlCommand info = (ControlCommand) object; + + info.setCommand("Command:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DataArrayResponseTest.java new file mode 100644 index 0000000000..1fe80fd5e7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DataArrayResponseTest.java @@ -0,0 +1,62 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DataArrayResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataArrayResponseTest extends ResponseTest { + + + public static DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); + + public Object createObject() throws Exception { + DataArrayResponse info = new DataArrayResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataArrayResponse info = (DataArrayResponse) object; + + { + DataStructure value[] = new DataStructure[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createDataStructure("Data:1"); + } + info.setData(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DataResponseTest.java new file mode 100644 index 0000000000..e7728ea0b1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DataResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DataResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DataResponseTest extends ResponseTest { + + + public static DataResponseTest SINGLETON = new DataResponseTest(); + + public Object createObject() throws Exception { + DataResponse info = new DataResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DataResponse info = (DataResponse) object; + + info.setData(createDataStructure("Data:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DestinationInfoTest.java new file mode 100644 index 0000000000..ac065e2fa9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DestinationInfoTest.java @@ -0,0 +1,66 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DestinationInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DestinationInfoTest extends BaseCommandTestSupport { + + + public static DestinationInfoTest SINGLETON = new DestinationInfoTest(); + + public Object createObject() throws Exception { + DestinationInfo info = new DestinationInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DestinationInfo info = (DestinationInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setOperationType((byte) 1); + info.setTimeout(1); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DiscoveryEventTest.java new file mode 100644 index 0000000000..de87bd95b8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/DiscoveryEventTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for DiscoveryEvent + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class DiscoveryEventTest extends DataFileGeneratorTestSupport { + + + public static DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); + + public Object createObject() throws Exception { + DiscoveryEvent info = new DiscoveryEvent(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + DiscoveryEvent info = (DiscoveryEvent) object; + + info.setServiceName("ServiceName:1"); + info.setBrokerName("BrokerName:2"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ExceptionResponseTest.java new file mode 100644 index 0000000000..9471dfd96d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ExceptionResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ExceptionResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ExceptionResponseTest extends ResponseTest { + + + public static ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); + + public Object createObject() throws Exception { + ExceptionResponse info = new ExceptionResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ExceptionResponse info = (ExceptionResponse) object; + + info.setException(createThrowable("Exception:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/FlushCommandTest.java new file mode 100644 index 0000000000..46f4bb403f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/FlushCommandTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for FlushCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class FlushCommandTest extends BaseCommandTestSupport { + + + public static FlushCommandTest SINGLETON = new FlushCommandTest(); + + public Object createObject() throws Exception { + FlushCommand info = new FlushCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + FlushCommand info = (FlushCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/IntegerResponseTest.java new file mode 100644 index 0000000000..999b047b81 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/IntegerResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for IntegerResponse + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class IntegerResponseTest extends ResponseTest { + + + public static IntegerResponseTest SINGLETON = new IntegerResponseTest(); + + public Object createObject() throws Exception { + IntegerResponse info = new IntegerResponse(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + IntegerResponse info = (IntegerResponse) object; + + info.setResult(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalQueueAckTest.java new file mode 100644 index 0000000000..7757277fa0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalQueueAckTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalQueueAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalQueueAckTest extends DataFileGeneratorTestSupport { + + + public static JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); + + public Object createObject() throws Exception { + JournalQueueAck info = new JournalQueueAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalQueueAck info = (JournalQueueAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageAck(createMessageAck("MessageAck:2")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTopicAckTest.java new file mode 100644 index 0000000000..dfcb65858e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTopicAckTest.java @@ -0,0 +1,61 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTopicAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTopicAckTest extends DataFileGeneratorTestSupport { + + + public static JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); + + public Object createObject() throws Exception { + JournalTopicAck info = new JournalTopicAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTopicAck info = (JournalTopicAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setMessageId(createMessageId("MessageId:2")); + info.setMessageSequenceId(1); + info.setSubscritionName("SubscritionName:3"); + info.setClientId("ClientId:4"); + info.setTransactionId(createTransactionId("TransactionId:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTraceTest.java new file mode 100644 index 0000000000..9406aeb030 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTraceTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTrace + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTraceTest extends DataFileGeneratorTestSupport { + + + public static JournalTraceTest SINGLETON = new JournalTraceTest(); + + public Object createObject() throws Exception { + JournalTrace info = new JournalTrace(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTrace info = (JournalTrace) object; + + info.setMessage("Message:1"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTransactionTest.java new file mode 100644 index 0000000000..d61fe9f2a5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/JournalTransactionTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for JournalTransaction + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class JournalTransactionTest extends DataFileGeneratorTestSupport { + + + public static JournalTransactionTest SINGLETON = new JournalTransactionTest(); + + public Object createObject() throws Exception { + JournalTransaction info = new JournalTransaction(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + JournalTransaction info = (JournalTransaction) object; + + info.setTransactionId(createTransactionId("TransactionId:1")); + info.setType((byte) 1); + info.setWasPrepared(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/KeepAliveInfoTest.java new file mode 100644 index 0000000000..67d61f0850 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/KeepAliveInfoTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for KeepAliveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class KeepAliveInfoTest extends BaseCommandTestSupport { + + + public static KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); + + public Object createObject() throws Exception { + KeepAliveInfo info = new KeepAliveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + KeepAliveInfo info = (KeepAliveInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/LastPartialCommandTest.java new file mode 100644 index 0000000000..4ede0f51b5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/LastPartialCommandTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for LastPartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LastPartialCommandTest extends PartialCommandTest { + + + public static LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); + + public Object createObject() throws Exception { + LastPartialCommand info = new LastPartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LastPartialCommand info = (LastPartialCommand) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/LocalTransactionIdTest.java new file mode 100644 index 0000000000..02ea10d0bb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/LocalTransactionIdTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for LocalTransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class LocalTransactionIdTest extends TransactionIdTestSupport { + + + public static LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); + + public Object createObject() throws Exception { + LocalTransactionId info = new LocalTransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + LocalTransactionId info = (LocalTransactionId) object; + + info.setValue(1); + info.setConnectionId(createConnectionId("ConnectionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageAckTest.java new file mode 100644 index 0000000000..b66c6ce106 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageAckTest.java @@ -0,0 +1,62 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageAckTest extends BaseCommandTestSupport { + + + public static MessageAckTest SINGLETON = new MessageAckTest(); + + public Object createObject() throws Exception { + MessageAck info = new MessageAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageAck info = (MessageAck) object; + + info.setDestination(createActiveMQDestination("Destination:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setConsumerId(createConsumerId("ConsumerId:3")); + info.setAckType((byte) 1); + info.setFirstMessageId(createMessageId("FirstMessageId:4")); + info.setLastMessageId(createMessageId("LastMessageId:5")); + info.setMessageCount(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..aa805cadca --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageDispatchNotificationTest.java @@ -0,0 +1,59 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageDispatchNotification + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchNotificationTest extends BaseCommandTestSupport { + + + public static MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); + + public Object createObject() throws Exception { + MessageDispatchNotification info = new MessageDispatchNotification(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatchNotification info = (MessageDispatchNotification) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setDeliverySequenceId(1); + info.setMessageId(createMessageId("MessageId:3")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageDispatchTest.java new file mode 100644 index 0000000000..bbc0459174 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageDispatchTest.java @@ -0,0 +1,59 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageDispatch + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageDispatchTest extends BaseCommandTestSupport { + + + public static MessageDispatchTest SINGLETON = new MessageDispatchTest(); + + public Object createObject() throws Exception { + MessageDispatch info = new MessageDispatch(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageDispatch info = (MessageDispatch) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setMessage(createMessage("Message:3")); + info.setRedeliveryCounter(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageIdTest.java new file mode 100644 index 0000000000..1f61361d57 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessageId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessageIdTest extends DataFileGeneratorTestSupport { + + + public static MessageIdTest SINGLETON = new MessageIdTest(); + + public Object createObject() throws Exception { + MessageId info = new MessageId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessageId info = (MessageId) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setProducerSequenceId(1); + info.setBrokerSequenceId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessagePullTest.java new file mode 100644 index 0000000000..f0d48a6269 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessagePullTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for MessagePull + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class MessagePullTest extends BaseCommandTestSupport { + + + public static MessagePullTest SINGLETON = new MessagePullTest(); + + public Object createObject() throws Exception { + MessagePull info = new MessagePull(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + MessagePull info = (MessagePull) object; + + info.setConsumerId(createConsumerId("ConsumerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTimeout(1); + info.setCorrelationId("CorrelationId:3"); + info.setMessageId(createMessageId("MessageId:4")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageTestSupport.java new file mode 100644 index 0000000000..863ee595c3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/MessageTestSupport.java @@ -0,0 +1,89 @@ +/** + * + * 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.openwire.v6; + +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for Message + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class MessageTestSupport extends BaseCommandTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Message info = (Message) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setTransactionId(createTransactionId("TransactionId:3")); + info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); + info.setMessageId(createMessageId("MessageId:5")); + info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); + info.setGroupID("GroupID:7"); + info.setGroupSequence(1); + info.setCorrelationId("CorrelationId:8"); + info.setPersistent(true); + info.setExpiration(1); + info.setPriority((byte) 1); + info.setReplyTo(createActiveMQDestination("ReplyTo:9")); + info.setTimestamp(2); + info.setType("Type:10"); + { + byte data[] = "Content:11".getBytes(); + info.setContent(new org.apache.activemq.util.ByteSequence(data,0,data.length)); +} + { + byte data[] = "MarshalledProperties:12".getBytes(); + info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data,0,data.length)); +} + info.setDataStructure(createDataStructure("DataStructure:13")); + info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); + info.setCompressed(false); + info.setRedeliveryCounter(2); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:15"); + } + info.setBrokerPath(value); + } + info.setArrival(3); + info.setUserID("UserID:16"); + info.setRecievedByDFBridge(true); + info.setDroppable(false); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("Cluster:17"); + } + info.setCluster(value); + } + info.setBrokerInTime(4); + info.setBrokerOutTime(5); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..e6bcf5433d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/NetworkBridgeFilterTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for NetworkBridgeFilter + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { + + + public static NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); + + public Object createObject() throws Exception { + NetworkBridgeFilter info = new NetworkBridgeFilter(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + NetworkBridgeFilter info = (NetworkBridgeFilter) object; + + info.setNetworkTTL(1); + info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/PartialCommandTest.java new file mode 100644 index 0000000000..2f0e8ee92a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/PartialCommandTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for PartialCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class PartialCommandTest extends DataFileGeneratorTestSupport { + + + public static PartialCommandTest SINGLETON = new PartialCommandTest(); + + public Object createObject() throws Exception { + PartialCommand info = new PartialCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + PartialCommand info = (PartialCommand) object; + + info.setCommandId(1); + info.setData("Data:1".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerAckTest.java new file mode 100644 index 0000000000..f4db4a95b0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerAckTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerAck + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerAckTest extends BaseCommandTestSupport { + + + public static ProducerAckTest SINGLETON = new ProducerAckTest(); + + public Object createObject() throws Exception { + ProducerAck info = new ProducerAck(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerAck info = (ProducerAck) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerIdTest.java new file mode 100644 index 0000000000..17c88d32dc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerIdTest extends DataFileGeneratorTestSupport { + + + public static ProducerIdTest SINGLETON = new ProducerIdTest(); + + public Object createObject() throws Exception { + ProducerId info = new ProducerId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerId info = (ProducerId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + info.setSessionId(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerInfoTest.java new file mode 100644 index 0000000000..d960980596 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ProducerInfoTest.java @@ -0,0 +1,66 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ProducerInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ProducerInfoTest extends BaseCommandTestSupport { + + + public static ProducerInfoTest SINGLETON = new ProducerInfoTest(); + + public Object createObject() throws Exception { + ProducerInfo info = new ProducerInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ProducerInfo info = (ProducerInfo) object; + + info.setProducerId(createProducerId("ProducerId:1")); + info.setDestination(createActiveMQDestination("Destination:2")); + { + BrokerId value[] = new BrokerId[2]; + for( int i=0; i < 2; i++ ) { + value[i] = createBrokerId("BrokerPath:3"); + } + info.setBrokerPath(value); + } + info.setDispatchAsync(true); + info.setWindowSize(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/RemoveInfoTest.java new file mode 100644 index 0000000000..503393589b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/RemoveInfoTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for RemoveInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveInfoTest extends BaseCommandTestSupport { + + + public static RemoveInfoTest SINGLETON = new RemoveInfoTest(); + + public Object createObject() throws Exception { + RemoveInfo info = new RemoveInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveInfo info = (RemoveInfo) object; + + info.setObjectId(createDataStructure("ObjectId:1")); + info.setLastDeliveredSequenceId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..9b86af573e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/RemoveSubscriptionInfoTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for RemoveSubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { + + + public static RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); + + public Object createObject() throws Exception { + RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setSubcriptionName("SubcriptionName:2"); + info.setClientId("ClientId:3"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ReplayCommandTest.java new file mode 100644 index 0000000000..d26de2529c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ReplayCommandTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ReplayCommand + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ReplayCommandTest extends BaseCommandTestSupport { + + + public static ReplayCommandTest SINGLETON = new ReplayCommandTest(); + + public Object createObject() throws Exception { + ReplayCommand info = new ReplayCommand(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ReplayCommand info = (ReplayCommand) object; + + info.setFirstNakNumber(1); + info.setLastNakNumber(2); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ResponseTest.java new file mode 100644 index 0000000000..8153f23ed5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ResponseTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for Response + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ResponseTest extends BaseCommandTestSupport { + + + public static ResponseTest SINGLETON = new ResponseTest(); + + public Object createObject() throws Exception { + Response info = new Response(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + Response info = (Response) object; + + info.setCorrelationId(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SessionIdTest.java new file mode 100644 index 0000000000..404fb200d3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SessionIdTest.java @@ -0,0 +1,57 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SessionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionIdTest extends DataFileGeneratorTestSupport { + + + public static SessionIdTest SINGLETON = new SessionIdTest(); + + public Object createObject() throws Exception { + SessionId info = new SessionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionId info = (SessionId) object; + + info.setConnectionId("ConnectionId:1"); + info.setValue(1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SessionInfoTest.java new file mode 100644 index 0000000000..2d69568542 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SessionInfoTest.java @@ -0,0 +1,56 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SessionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SessionInfoTest extends BaseCommandTestSupport { + + + public static SessionInfoTest SINGLETON = new SessionInfoTest(); + + public Object createObject() throws Exception { + SessionInfo info = new SessionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SessionInfo info = (SessionInfo) object; + + info.setSessionId(createSessionId("SessionId:1")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ShutdownInfoTest.java new file mode 100644 index 0000000000..5a90219b32 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/ShutdownInfoTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for ShutdownInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class ShutdownInfoTest extends BaseCommandTestSupport { + + + public static ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); + + public Object createObject() throws Exception { + ShutdownInfo info = new ShutdownInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + ShutdownInfo info = (ShutdownInfo) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SubscriptionInfoTest.java new file mode 100644 index 0000000000..df5e24ee73 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/SubscriptionInfoTest.java @@ -0,0 +1,60 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for SubscriptionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { + + + public static SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); + + public Object createObject() throws Exception { + SubscriptionInfo info = new SubscriptionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + SubscriptionInfo info = (SubscriptionInfo) object; + + info.setClientId("ClientId:1"); + info.setDestination(createActiveMQDestination("Destination:2")); + info.setSelector("Selector:3"); + info.setSubcriptionName("SubcriptionName:4"); + info.setSubscribedDestination(createActiveMQDestination("SubscribedDestination:5")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/TransactionIdTestSupport.java new file mode 100644 index 0000000000..f2f0ec967e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/TransactionIdTestSupport.java @@ -0,0 +1,47 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for TransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { + + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionId info = (TransactionId) object; + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/TransactionInfoTest.java new file mode 100644 index 0000000000..fb4e5ca54e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/TransactionInfoTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for TransactionInfo + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class TransactionInfoTest extends BaseCommandTestSupport { + + + public static TransactionInfoTest SINGLETON = new TransactionInfoTest(); + + public Object createObject() throws Exception { + TransactionInfo info = new TransactionInfo(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + TransactionInfo info = (TransactionInfo) object; + + info.setConnectionId(createConnectionId("ConnectionId:1")); + info.setTransactionId(createTransactionId("TransactionId:2")); + info.setType((byte) 1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/XATransactionIdTest.java new file mode 100644 index 0000000000..c4e1c04c88 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v6/XATransactionIdTest.java @@ -0,0 +1,58 @@ +/** + * + * 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.openwire.v6; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.activemq.openwire.*; +import org.apache.activemq.command.*; + + +/** + * Test case for the OpenWire marshalling for XATransactionId + * + * + * NOTE!: This file is auto generated - do not modify! + * if you need to make a change, please see the modify the groovy scripts in the + * under src/gram/script and then use maven openwire:generate to regenerate + * this file. + * + * + */ +public class XATransactionIdTest extends TransactionIdTestSupport { + + + public static XATransactionIdTest SINGLETON = new XATransactionIdTest(); + + public Object createObject() throws Exception { + XATransactionId info = new XATransactionId(); + populateObject(info); + return info; + } + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + XATransactionId info = (XATransactionId) object; + + info.setFormatId(1); + info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); + info.setBranchQualifier("BranchQualifier:2".getBytes()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BaseCommandTestSupport.java new file mode 100644 index 0000000000..f741fba52a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BaseCommandTestSupport.java @@ -0,0 +1,38 @@ +/** + * 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.openwire.v7; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BrokerIdTest.java new file mode 100644 index 0000000000..b701693dee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BrokerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for BrokerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class BrokerIdTest extends DataFileGeneratorTestSupport { public static BrokerIdTest SINGLETON = new BrokerIdTest(); public Object createObject() throws Exception { BrokerId info = new BrokerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); BrokerId info = (BrokerId) object; info.setValue("Value:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BrokerInfoTest.java new file mode 100644 index 0000000000..657e60f896 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/BrokerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for BrokerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class BrokerInfoTest extends BaseCommandTestSupport { public static BrokerInfoTest SINGLETON = new BrokerInfoTest(); public Object createObject() throws Exception { BrokerInfo info = new BrokerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); BrokerInfo info = (BrokerInfo) object; info.setBrokerId(createBrokerId("BrokerId:1")); info.setBrokerURL("BrokerURL:2"); { BrokerInfo value[] = new BrokerInfo[0]; for( int i=0; i < 0; i++ ) { value[i] = createBrokerInfo("PeerBrokerInfos:3"); } info.setPeerBrokerInfos(value); } info.setBrokerName("BrokerName:4"); info.setSlaveBroker(true); info.setMasterBroker(false); info.setFaultTolerantConfiguration(true); info.setDuplexConnection(false); info.setNetworkConnection(true); info.setConnectionId(1); info.setBrokerUploadUrl("BrokerUploadUrl:5"); info.setNetworkProperties("NetworkProperties:6"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionControlTest.java new file mode 100644 index 0000000000..cff204ea60 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionControlTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionControl * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionControlTest extends BaseCommandTestSupport { public static ConnectionControlTest SINGLETON = new ConnectionControlTest(); public Object createObject() throws Exception { ConnectionControl info = new ConnectionControl(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionControl info = (ConnectionControl) object; info.setClose(true); info.setExit(false); info.setFaultTolerant(true); info.setResume(false); info.setSuspend(true); info.setConnectedBrokers("ConnectedBrokers:1"); info.setReconnectTo("ReconnectTo:2"); info.setRebalanceConnection(false); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionErrorTest.java new file mode 100644 index 0000000000..46cfa3c891 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionErrorTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionError * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionErrorTest extends BaseCommandTestSupport { public static ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); public Object createObject() throws Exception { ConnectionError info = new ConnectionError(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionError info = (ConnectionError) object; info.setException(createThrowable("Exception:1")); info.setConnectionId(createConnectionId("ConnectionId:2")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionIdTest.java new file mode 100644 index 0000000000..54fc16ce43 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionIdTest extends DataFileGeneratorTestSupport { public static ConnectionIdTest SINGLETON = new ConnectionIdTest(); public Object createObject() throws Exception { ConnectionId info = new ConnectionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionId info = (ConnectionId) object; info.setValue("Value:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionInfoTest.java new file mode 100644 index 0000000000..c059052b7c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConnectionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionInfoTest extends BaseCommandTestSupport { public static ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); public Object createObject() throws Exception { ConnectionInfo info = new ConnectionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionInfo info = (ConnectionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setClientId("ClientId:2"); info.setPassword("Password:3"); info.setUserName("UserName:4"); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:5"); } info.setBrokerPath(value); } info.setBrokerMasterConnector(true); info.setManageable(false); info.setClientMaster(true); info.setFaultTolerant(false); info.setFailoverReconnect(true); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerControlTest.java new file mode 100644 index 0000000000..df1b48089d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerControlTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerControl * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerControlTest extends BaseCommandTestSupport { public static ConsumerControlTest SINGLETON = new ConsumerControlTest(); public Object createObject() throws Exception { ConsumerControl info = new ConsumerControl(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerControl info = (ConsumerControl) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setClose(true); info.setConsumerId(createConsumerId("ConsumerId:2")); info.setPrefetch(1); info.setFlush(false); info.setStart(true); info.setStop(false); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerIdTest.java new file mode 100644 index 0000000000..32db0ac4ce --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerIdTest extends DataFileGeneratorTestSupport { public static ConsumerIdTest SINGLETON = new ConsumerIdTest(); public Object createObject() throws Exception { ConsumerId info = new ConsumerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerId info = (ConsumerId) object; info.setConnectionId("ConnectionId:1"); info.setSessionId(1); info.setValue(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerInfoTest.java new file mode 100644 index 0000000000..e3a120712e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ConsumerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerInfoTest extends BaseCommandTestSupport { public static ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); public Object createObject() throws Exception { ConsumerInfo info = new ConsumerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerInfo info = (ConsumerInfo) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setBrowser(true); info.setDestination(createActiveMQDestination("Destination:2")); info.setPrefetchSize(1); info.setMaximumPendingMessageLimit(2); info.setDispatchAsync(false); info.setSelector("Selector:3"); info.setSubscriptionName("SubscriptionName:4"); info.setNoLocal(true); info.setExclusive(false); info.setRetroactive(true); info.setPriority((byte) 1); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:5"); } info.setBrokerPath(value); } info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); info.setNetworkSubscription(false); info.setOptimizedAcknowledge(true); info.setNoRangeAcks(false); { ConsumerId value[] = new ConsumerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createConsumerId("NetworkConsumerPath:7"); } info.setNetworkConsumerPath(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ControlCommandTest.java new file mode 100644 index 0000000000..ca402e634e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ControlCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ControlCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ControlCommandTest extends BaseCommandTestSupport { public static ControlCommandTest SINGLETON = new ControlCommandTest(); public Object createObject() throws Exception { ControlCommand info = new ControlCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ControlCommand info = (ControlCommand) object; info.setCommand("Command:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DataArrayResponseTest.java new file mode 100644 index 0000000000..67e23c6a1e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DataArrayResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DataArrayResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DataArrayResponseTest extends ResponseTest { public static DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); public Object createObject() throws Exception { DataArrayResponse info = new DataArrayResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DataArrayResponse info = (DataArrayResponse) object; { DataStructure value[] = new DataStructure[2]; for( int i=0; i < 2; i++ ) { value[i] = createDataStructure("Data:1"); } info.setData(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DataResponseTest.java new file mode 100644 index 0000000000..ef239cebc5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DataResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DataResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DataResponseTest extends ResponseTest { public static DataResponseTest SINGLETON = new DataResponseTest(); public Object createObject() throws Exception { DataResponse info = new DataResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DataResponse info = (DataResponse) object; info.setData(createDataStructure("Data:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DestinationInfoTest.java new file mode 100644 index 0000000000..3d36583e0e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DestinationInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DestinationInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DestinationInfoTest extends BaseCommandTestSupport { public static DestinationInfoTest SINGLETON = new DestinationInfoTest(); public Object createObject() throws Exception { DestinationInfo info = new DestinationInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DestinationInfo info = (DestinationInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setOperationType((byte) 1); info.setTimeout(1); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:3"); } info.setBrokerPath(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DiscoveryEventTest.java new file mode 100644 index 0000000000..939ed8ca0c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/DiscoveryEventTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DiscoveryEvent * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DiscoveryEventTest extends DataFileGeneratorTestSupport { public static DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); public Object createObject() throws Exception { DiscoveryEvent info = new DiscoveryEvent(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DiscoveryEvent info = (DiscoveryEvent) object; info.setServiceName("ServiceName:1"); info.setBrokerName("BrokerName:2"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ExceptionResponseTest.java new file mode 100644 index 0000000000..d05f91867d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ExceptionResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ExceptionResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ExceptionResponseTest extends ResponseTest { public static ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); public Object createObject() throws Exception { ExceptionResponse info = new ExceptionResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ExceptionResponse info = (ExceptionResponse) object; info.setException(createThrowable("Exception:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/FlushCommandTest.java new file mode 100644 index 0000000000..21275c7ec8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/FlushCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for FlushCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class FlushCommandTest extends BaseCommandTestSupport { public static FlushCommandTest SINGLETON = new FlushCommandTest(); public Object createObject() throws Exception { FlushCommand info = new FlushCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); FlushCommand info = (FlushCommand) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/IntegerResponseTest.java new file mode 100644 index 0000000000..88c6e33f90 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/IntegerResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for IntegerResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class IntegerResponseTest extends ResponseTest { public static IntegerResponseTest SINGLETON = new IntegerResponseTest(); public Object createObject() throws Exception { IntegerResponse info = new IntegerResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); IntegerResponse info = (IntegerResponse) object; info.setResult(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalQueueAckTest.java new file mode 100644 index 0000000000..f12c69cd55 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalQueueAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalQueueAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalQueueAckTest extends DataFileGeneratorTestSupport { public static JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); public Object createObject() throws Exception { JournalQueueAck info = new JournalQueueAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalQueueAck info = (JournalQueueAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setMessageAck(createMessageAck("MessageAck:2")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTopicAckTest.java new file mode 100644 index 0000000000..fe48a8d314 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTopicAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTopicAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTopicAckTest extends DataFileGeneratorTestSupport { public static JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); public Object createObject() throws Exception { JournalTopicAck info = new JournalTopicAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTopicAck info = (JournalTopicAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setMessageId(createMessageId("MessageId:2")); info.setMessageSequenceId(1); info.setSubscritionName("SubscritionName:3"); info.setClientId("ClientId:4"); info.setTransactionId(createTransactionId("TransactionId:5")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTraceTest.java new file mode 100644 index 0000000000..fce7d59d9a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTraceTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTrace * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTraceTest extends DataFileGeneratorTestSupport { public static JournalTraceTest SINGLETON = new JournalTraceTest(); public Object createObject() throws Exception { JournalTrace info = new JournalTrace(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTrace info = (JournalTrace) object; info.setMessage("Message:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTransactionTest.java new file mode 100644 index 0000000000..8b9bd07c0c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/JournalTransactionTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTransaction * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTransactionTest extends DataFileGeneratorTestSupport { public static JournalTransactionTest SINGLETON = new JournalTransactionTest(); public Object createObject() throws Exception { JournalTransaction info = new JournalTransaction(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTransaction info = (JournalTransaction) object; info.setTransactionId(createTransactionId("TransactionId:1")); info.setType((byte) 1); info.setWasPrepared(true); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/KeepAliveInfoTest.java new file mode 100644 index 0000000000..ba6a23afb2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/KeepAliveInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for KeepAliveInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class KeepAliveInfoTest extends BaseCommandTestSupport { public static KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); public Object createObject() throws Exception { KeepAliveInfo info = new KeepAliveInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); KeepAliveInfo info = (KeepAliveInfo) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/LastPartialCommandTest.java new file mode 100644 index 0000000000..9e5922dca2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/LastPartialCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for LastPartialCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class LastPartialCommandTest extends PartialCommandTest { public static LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); public Object createObject() throws Exception { LastPartialCommand info = new LastPartialCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); LastPartialCommand info = (LastPartialCommand) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/LocalTransactionIdTest.java new file mode 100644 index 0000000000..c70c948f1e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/LocalTransactionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for LocalTransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class LocalTransactionIdTest extends TransactionIdTestSupport { public static LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); public Object createObject() throws Exception { LocalTransactionId info = new LocalTransactionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); LocalTransactionId info = (LocalTransactionId) object; info.setValue(1); info.setConnectionId(createConnectionId("ConnectionId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageAckTest.java new file mode 100644 index 0000000000..8a00f6e3f7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageAckTest extends BaseCommandTestSupport { public static MessageAckTest SINGLETON = new MessageAckTest(); public Object createObject() throws Exception { MessageAck info = new MessageAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageAck info = (MessageAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setTransactionId(createTransactionId("TransactionId:2")); info.setConsumerId(createConsumerId("ConsumerId:3")); info.setAckType((byte) 1); info.setFirstMessageId(createMessageId("FirstMessageId:4")); info.setLastMessageId(createMessageId("LastMessageId:5")); info.setMessageCount(1); info.setPoisonCause(createThrowable("PoisonCause:6")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..b661a2362a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageDispatchNotificationTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageDispatchNotification * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageDispatchNotificationTest extends BaseCommandTestSupport { public static MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); public Object createObject() throws Exception { MessageDispatchNotification info = new MessageDispatchNotification(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageDispatchNotification info = (MessageDispatchNotification) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setDeliverySequenceId(1); info.setMessageId(createMessageId("MessageId:3")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageDispatchTest.java new file mode 100644 index 0000000000..05a038494f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageDispatchTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageDispatch * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageDispatchTest extends BaseCommandTestSupport { public static MessageDispatchTest SINGLETON = new MessageDispatchTest(); public Object createObject() throws Exception { MessageDispatch info = new MessageDispatch(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageDispatch info = (MessageDispatch) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setMessage(createMessage("Message:3")); info.setRedeliveryCounter(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageIdTest.java new file mode 100644 index 0000000000..484b0377e1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageIdTest extends DataFileGeneratorTestSupport { public static MessageIdTest SINGLETON = new MessageIdTest(); public Object createObject() throws Exception { MessageId info = new MessageId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageId info = (MessageId) object; info.setProducerId(createProducerId("ProducerId:1")); info.setProducerSequenceId(1); info.setBrokerSequenceId(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessagePullTest.java new file mode 100644 index 0000000000..279c089836 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessagePullTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessagePull * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessagePullTest extends BaseCommandTestSupport { public static MessagePullTest SINGLETON = new MessagePullTest(); public Object createObject() throws Exception { MessagePull info = new MessagePull(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessagePull info = (MessagePull) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setTimeout(1); info.setCorrelationId("CorrelationId:3"); info.setMessageId(createMessageId("MessageId:4")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageTestSupport.java new file mode 100644 index 0000000000..a5d4f3b52c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/MessageTestSupport.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for Message * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public abstract class MessageTestSupport extends BaseCommandTestSupport { protected void populateObject(Object object) throws Exception { super.populateObject(object); Message info = (Message) object; info.setProducerId(createProducerId("ProducerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setTransactionId(createTransactionId("TransactionId:3")); info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); info.setMessageId(createMessageId("MessageId:5")); info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); info.setGroupID("GroupID:7"); info.setGroupSequence(1); info.setCorrelationId("CorrelationId:8"); info.setPersistent(true); info.setExpiration(1); info.setPriority((byte) 1); info.setReplyTo(createActiveMQDestination("ReplyTo:9")); info.setTimestamp(2); info.setType("Type:10"); { byte data[] = "Content:11".getBytes(); info.setContent(new org.apache.activemq.util.ByteSequence(data,0,data.length)); } { byte data[] = "MarshalledProperties:12".getBytes(); info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data,0,data.length)); } info.setDataStructure(createDataStructure("DataStructure:13")); info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); info.setCompressed(false); info.setRedeliveryCounter(2); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:15"); } info.setBrokerPath(value); } info.setArrival(3); info.setUserID("UserID:16"); info.setRecievedByDFBridge(true); info.setDroppable(false); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("Cluster:17"); } info.setCluster(value); } info.setBrokerInTime(4); info.setBrokerOutTime(5); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..3cb5e249c8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/NetworkBridgeFilterTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for NetworkBridgeFilter * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { public static NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); public Object createObject() throws Exception { NetworkBridgeFilter info = new NetworkBridgeFilter(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); NetworkBridgeFilter info = (NetworkBridgeFilter) object; info.setNetworkTTL(1); info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/PartialCommandTest.java new file mode 100644 index 0000000000..dceac8370d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/PartialCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for PartialCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class PartialCommandTest extends DataFileGeneratorTestSupport { public static PartialCommandTest SINGLETON = new PartialCommandTest(); public Object createObject() throws Exception { PartialCommand info = new PartialCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); PartialCommand info = (PartialCommand) object; info.setCommandId(1); info.setData("Data:1".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerAckTest.java new file mode 100644 index 0000000000..73104563e7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerAckTest extends BaseCommandTestSupport { public static ProducerAckTest SINGLETON = new ProducerAckTest(); public Object createObject() throws Exception { ProducerAck info = new ProducerAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerAck info = (ProducerAck) object; info.setProducerId(createProducerId("ProducerId:1")); info.setSize(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerIdTest.java new file mode 100644 index 0000000000..2a8c13ba18 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerIdTest extends DataFileGeneratorTestSupport { public static ProducerIdTest SINGLETON = new ProducerIdTest(); public Object createObject() throws Exception { ProducerId info = new ProducerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerId info = (ProducerId) object; info.setConnectionId("ConnectionId:1"); info.setValue(1); info.setSessionId(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerInfoTest.java new file mode 100644 index 0000000000..474a55eaa2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ProducerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerInfoTest extends BaseCommandTestSupport { public static ProducerInfoTest SINGLETON = new ProducerInfoTest(); public Object createObject() throws Exception { ProducerInfo info = new ProducerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerInfo info = (ProducerInfo) object; info.setProducerId(createProducerId("ProducerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:3"); } info.setBrokerPath(value); } info.setDispatchAsync(true); info.setWindowSize(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/RemoveInfoTest.java new file mode 100644 index 0000000000..01b2639acf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/RemoveInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for RemoveInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class RemoveInfoTest extends BaseCommandTestSupport { public static RemoveInfoTest SINGLETON = new RemoveInfoTest(); public Object createObject() throws Exception { RemoveInfo info = new RemoveInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); RemoveInfo info = (RemoveInfo) object; info.setObjectId(createDataStructure("ObjectId:1")); info.setLastDeliveredSequenceId(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..4159ee6e15 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/RemoveSubscriptionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for RemoveSubscriptionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { public static RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); public Object createObject() throws Exception { RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setSubcriptionName("SubcriptionName:2"); info.setClientId("ClientId:3"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ReplayCommandTest.java new file mode 100644 index 0000000000..8a1e8e2af6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ReplayCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ReplayCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ReplayCommandTest extends BaseCommandTestSupport { public static ReplayCommandTest SINGLETON = new ReplayCommandTest(); public Object createObject() throws Exception { ReplayCommand info = new ReplayCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ReplayCommand info = (ReplayCommand) object; info.setFirstNakNumber(1); info.setLastNakNumber(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ResponseTest.java new file mode 100644 index 0000000000..1d64767b99 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for Response * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ResponseTest extends BaseCommandTestSupport { public static ResponseTest SINGLETON = new ResponseTest(); public Object createObject() throws Exception { Response info = new Response(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); Response info = (Response) object; info.setCorrelationId(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SessionIdTest.java new file mode 100644 index 0000000000..d12c96478d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SessionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SessionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SessionIdTest extends DataFileGeneratorTestSupport { public static SessionIdTest SINGLETON = new SessionIdTest(); public Object createObject() throws Exception { SessionId info = new SessionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SessionId info = (SessionId) object; info.setConnectionId("ConnectionId:1"); info.setValue(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SessionInfoTest.java new file mode 100644 index 0000000000..cee5c070bd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SessionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SessionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SessionInfoTest extends BaseCommandTestSupport { public static SessionInfoTest SINGLETON = new SessionInfoTest(); public Object createObject() throws Exception { SessionInfo info = new SessionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SessionInfo info = (SessionInfo) object; info.setSessionId(createSessionId("SessionId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ShutdownInfoTest.java new file mode 100644 index 0000000000..66dda57be4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/ShutdownInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ShutdownInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ShutdownInfoTest extends BaseCommandTestSupport { public static ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); public Object createObject() throws Exception { ShutdownInfo info = new ShutdownInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ShutdownInfo info = (ShutdownInfo) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SubscriptionInfoTest.java new file mode 100644 index 0000000000..0a9e9344e5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/SubscriptionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SubscriptionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { public static SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); public Object createObject() throws Exception { SubscriptionInfo info = new SubscriptionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SubscriptionInfo info = (SubscriptionInfo) object; info.setClientId("ClientId:1"); info.setDestination(createActiveMQDestination("Destination:2")); info.setSelector("Selector:3"); info.setSubcriptionName("SubcriptionName:4"); info.setSubscribedDestination(createActiveMQDestination("SubscribedDestination:5")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/TransactionIdTestSupport.java new file mode 100644 index 0000000000..9706f12e27 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/TransactionIdTestSupport.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for TransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { protected void populateObject(Object object) throws Exception { super.populateObject(object); TransactionId info = (TransactionId) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/TransactionInfoTest.java new file mode 100644 index 0000000000..3132a2b15e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/TransactionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for TransactionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class TransactionInfoTest extends BaseCommandTestSupport { public static TransactionInfoTest SINGLETON = new TransactionInfoTest(); public Object createObject() throws Exception { TransactionInfo info = new TransactionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); TransactionInfo info = (TransactionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setTransactionId(createTransactionId("TransactionId:2")); info.setType((byte) 1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/XATransactionIdTest.java new file mode 100644 index 0000000000..79db31688b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v7/XATransactionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v7; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for XATransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class XATransactionIdTest extends TransactionIdTestSupport { public static XATransactionIdTest SINGLETON = new XATransactionIdTest(); public Object createObject() throws Exception { XATransactionId info = new XATransactionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); XATransactionId info = (XATransactionId) object; info.setFormatId(1); info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); info.setBranchQualifier("BranchQualifier:2".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BaseCommandTestSupport.java new file mode 100644 index 0000000000..478d93d618 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BaseCommandTestSupport.java @@ -0,0 +1,38 @@ +/** + * 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.openwire.v8; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BrokerIdTest.java new file mode 100644 index 0000000000..afa21c97b9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BrokerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for BrokerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class BrokerIdTest extends DataFileGeneratorTestSupport { public static BrokerIdTest SINGLETON = new BrokerIdTest(); public Object createObject() throws Exception { BrokerId info = new BrokerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); BrokerId info = (BrokerId) object; info.setValue("Value:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BrokerInfoTest.java new file mode 100644 index 0000000000..acdd9fafe5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/BrokerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for BrokerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class BrokerInfoTest extends BaseCommandTestSupport { public static BrokerInfoTest SINGLETON = new BrokerInfoTest(); public Object createObject() throws Exception { BrokerInfo info = new BrokerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); BrokerInfo info = (BrokerInfo) object; info.setBrokerId(createBrokerId("BrokerId:1")); info.setBrokerURL("BrokerURL:2"); { BrokerInfo value[] = new BrokerInfo[0]; for( int i=0; i < 0; i++ ) { value[i] = createBrokerInfo("PeerBrokerInfos:3"); } info.setPeerBrokerInfos(value); } info.setBrokerName("BrokerName:4"); info.setSlaveBroker(true); info.setMasterBroker(false); info.setFaultTolerantConfiguration(true); info.setDuplexConnection(false); info.setNetworkConnection(true); info.setConnectionId(1); info.setBrokerUploadUrl("BrokerUploadUrl:5"); info.setNetworkProperties("NetworkProperties:6"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionControlTest.java new file mode 100644 index 0000000000..64ef24ddc8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionControlTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionControl * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionControlTest extends BaseCommandTestSupport { public static ConnectionControlTest SINGLETON = new ConnectionControlTest(); public Object createObject() throws Exception { ConnectionControl info = new ConnectionControl(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionControl info = (ConnectionControl) object; info.setClose(true); info.setExit(false); info.setFaultTolerant(true); info.setResume(false); info.setSuspend(true); info.setConnectedBrokers("ConnectedBrokers:1"); info.setReconnectTo("ReconnectTo:2"); info.setRebalanceConnection(false); info.setToken("Token:3".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionErrorTest.java new file mode 100644 index 0000000000..857746c202 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionErrorTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionError * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionErrorTest extends BaseCommandTestSupport { public static ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); public Object createObject() throws Exception { ConnectionError info = new ConnectionError(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionError info = (ConnectionError) object; info.setException(createThrowable("Exception:1")); info.setConnectionId(createConnectionId("ConnectionId:2")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionIdTest.java new file mode 100644 index 0000000000..6c45427cc0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionIdTest extends DataFileGeneratorTestSupport { public static ConnectionIdTest SINGLETON = new ConnectionIdTest(); public Object createObject() throws Exception { ConnectionId info = new ConnectionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionId info = (ConnectionId) object; info.setValue("Value:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionInfoTest.java new file mode 100644 index 0000000000..b10259ebde --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConnectionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionInfoTest extends BaseCommandTestSupport { public static ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); public Object createObject() throws Exception { ConnectionInfo info = new ConnectionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionInfo info = (ConnectionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setClientId("ClientId:2"); info.setPassword("Password:3"); info.setUserName("UserName:4"); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:5"); } info.setBrokerPath(value); } info.setBrokerMasterConnector(true); info.setManageable(false); info.setClientMaster(true); info.setFaultTolerant(false); info.setFailoverReconnect(true); info.setClientIp("ClientIp:6"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerControlTest.java new file mode 100644 index 0000000000..7d0917ef91 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerControlTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerControl * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerControlTest extends BaseCommandTestSupport { public static ConsumerControlTest SINGLETON = new ConsumerControlTest(); public Object createObject() throws Exception { ConsumerControl info = new ConsumerControl(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerControl info = (ConsumerControl) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setClose(true); info.setConsumerId(createConsumerId("ConsumerId:2")); info.setPrefetch(1); info.setFlush(false); info.setStart(true); info.setStop(false); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerIdTest.java new file mode 100644 index 0000000000..6e5b66dd21 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerIdTest extends DataFileGeneratorTestSupport { public static ConsumerIdTest SINGLETON = new ConsumerIdTest(); public Object createObject() throws Exception { ConsumerId info = new ConsumerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerId info = (ConsumerId) object; info.setConnectionId("ConnectionId:1"); info.setSessionId(1); info.setValue(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerInfoTest.java new file mode 100644 index 0000000000..a1e8695ba3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ConsumerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerInfoTest extends BaseCommandTestSupport { public static ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); public Object createObject() throws Exception { ConsumerInfo info = new ConsumerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerInfo info = (ConsumerInfo) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setBrowser(true); info.setDestination(createActiveMQDestination("Destination:2")); info.setPrefetchSize(1); info.setMaximumPendingMessageLimit(2); info.setDispatchAsync(false); info.setSelector("Selector:3"); info.setSubscriptionName("SubscriptionName:4"); info.setNoLocal(true); info.setExclusive(false); info.setRetroactive(true); info.setPriority((byte) 1); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:5"); } info.setBrokerPath(value); } info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); info.setNetworkSubscription(false); info.setOptimizedAcknowledge(true); info.setNoRangeAcks(false); { ConsumerId value[] = new ConsumerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createConsumerId("NetworkConsumerPath:7"); } info.setNetworkConsumerPath(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ControlCommandTest.java new file mode 100644 index 0000000000..be712161fe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ControlCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ControlCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ControlCommandTest extends BaseCommandTestSupport { public static ControlCommandTest SINGLETON = new ControlCommandTest(); public Object createObject() throws Exception { ControlCommand info = new ControlCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ControlCommand info = (ControlCommand) object; info.setCommand("Command:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DataArrayResponseTest.java new file mode 100644 index 0000000000..b2a0d15370 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DataArrayResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DataArrayResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DataArrayResponseTest extends ResponseTest { public static DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); public Object createObject() throws Exception { DataArrayResponse info = new DataArrayResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DataArrayResponse info = (DataArrayResponse) object; { DataStructure value[] = new DataStructure[2]; for( int i=0; i < 2; i++ ) { value[i] = createDataStructure("Data:1"); } info.setData(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DataResponseTest.java new file mode 100644 index 0000000000..2806a893a0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DataResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DataResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DataResponseTest extends ResponseTest { public static DataResponseTest SINGLETON = new DataResponseTest(); public Object createObject() throws Exception { DataResponse info = new DataResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DataResponse info = (DataResponse) object; info.setData(createDataStructure("Data:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DestinationInfoTest.java new file mode 100644 index 0000000000..5c94e91feb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DestinationInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DestinationInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DestinationInfoTest extends BaseCommandTestSupport { public static DestinationInfoTest SINGLETON = new DestinationInfoTest(); public Object createObject() throws Exception { DestinationInfo info = new DestinationInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DestinationInfo info = (DestinationInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setOperationType((byte) 1); info.setTimeout(1); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:3"); } info.setBrokerPath(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DiscoveryEventTest.java new file mode 100644 index 0000000000..3264cd4b51 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/DiscoveryEventTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DiscoveryEvent * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DiscoveryEventTest extends DataFileGeneratorTestSupport { public static DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); public Object createObject() throws Exception { DiscoveryEvent info = new DiscoveryEvent(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DiscoveryEvent info = (DiscoveryEvent) object; info.setServiceName("ServiceName:1"); info.setBrokerName("BrokerName:2"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ExceptionResponseTest.java new file mode 100644 index 0000000000..bb082a90a2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ExceptionResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ExceptionResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ExceptionResponseTest extends ResponseTest { public static ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); public Object createObject() throws Exception { ExceptionResponse info = new ExceptionResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ExceptionResponse info = (ExceptionResponse) object; info.setException(createThrowable("Exception:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/FlushCommandTest.java new file mode 100644 index 0000000000..e84280bc1d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/FlushCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for FlushCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class FlushCommandTest extends BaseCommandTestSupport { public static FlushCommandTest SINGLETON = new FlushCommandTest(); public Object createObject() throws Exception { FlushCommand info = new FlushCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); FlushCommand info = (FlushCommand) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/IntegerResponseTest.java new file mode 100644 index 0000000000..5b4c12a704 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/IntegerResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for IntegerResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class IntegerResponseTest extends ResponseTest { public static IntegerResponseTest SINGLETON = new IntegerResponseTest(); public Object createObject() throws Exception { IntegerResponse info = new IntegerResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); IntegerResponse info = (IntegerResponse) object; info.setResult(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalQueueAckTest.java new file mode 100644 index 0000000000..5b69667005 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalQueueAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalQueueAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalQueueAckTest extends DataFileGeneratorTestSupport { public static JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); public Object createObject() throws Exception { JournalQueueAck info = new JournalQueueAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalQueueAck info = (JournalQueueAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setMessageAck(createMessageAck("MessageAck:2")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTopicAckTest.java new file mode 100644 index 0000000000..120686970b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTopicAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTopicAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTopicAckTest extends DataFileGeneratorTestSupport { public static JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); public Object createObject() throws Exception { JournalTopicAck info = new JournalTopicAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTopicAck info = (JournalTopicAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setMessageId(createMessageId("MessageId:2")); info.setMessageSequenceId(1); info.setSubscritionName("SubscritionName:3"); info.setClientId("ClientId:4"); info.setTransactionId(createTransactionId("TransactionId:5")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTraceTest.java new file mode 100644 index 0000000000..9172fcc561 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTraceTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTrace * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTraceTest extends DataFileGeneratorTestSupport { public static JournalTraceTest SINGLETON = new JournalTraceTest(); public Object createObject() throws Exception { JournalTrace info = new JournalTrace(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTrace info = (JournalTrace) object; info.setMessage("Message:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTransactionTest.java new file mode 100644 index 0000000000..1216bed8d2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/JournalTransactionTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTransaction * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTransactionTest extends DataFileGeneratorTestSupport { public static JournalTransactionTest SINGLETON = new JournalTransactionTest(); public Object createObject() throws Exception { JournalTransaction info = new JournalTransaction(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTransaction info = (JournalTransaction) object; info.setTransactionId(createTransactionId("TransactionId:1")); info.setType((byte) 1); info.setWasPrepared(true); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/KeepAliveInfoTest.java new file mode 100644 index 0000000000..9d39ae3ab8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/KeepAliveInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for KeepAliveInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class KeepAliveInfoTest extends BaseCommandTestSupport { public static KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); public Object createObject() throws Exception { KeepAliveInfo info = new KeepAliveInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); KeepAliveInfo info = (KeepAliveInfo) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/LastPartialCommandTest.java new file mode 100644 index 0000000000..1c36b25aff --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/LastPartialCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for LastPartialCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class LastPartialCommandTest extends PartialCommandTest { public static LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); public Object createObject() throws Exception { LastPartialCommand info = new LastPartialCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); LastPartialCommand info = (LastPartialCommand) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/LocalTransactionIdTest.java new file mode 100644 index 0000000000..b2b1c8148d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/LocalTransactionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for LocalTransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class LocalTransactionIdTest extends TransactionIdTestSupport { public static LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); public Object createObject() throws Exception { LocalTransactionId info = new LocalTransactionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); LocalTransactionId info = (LocalTransactionId) object; info.setValue(1); info.setConnectionId(createConnectionId("ConnectionId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageAckTest.java new file mode 100644 index 0000000000..ba6efc1fc4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageAckTest extends BaseCommandTestSupport { public static MessageAckTest SINGLETON = new MessageAckTest(); public Object createObject() throws Exception { MessageAck info = new MessageAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageAck info = (MessageAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setTransactionId(createTransactionId("TransactionId:2")); info.setConsumerId(createConsumerId("ConsumerId:3")); info.setAckType((byte) 1); info.setFirstMessageId(createMessageId("FirstMessageId:4")); info.setLastMessageId(createMessageId("LastMessageId:5")); info.setMessageCount(1); info.setPoisonCause(createThrowable("PoisonCause:6")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..1ff388cb70 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageDispatchNotificationTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageDispatchNotification * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageDispatchNotificationTest extends BaseCommandTestSupport { public static MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); public Object createObject() throws Exception { MessageDispatchNotification info = new MessageDispatchNotification(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageDispatchNotification info = (MessageDispatchNotification) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setDeliverySequenceId(1); info.setMessageId(createMessageId("MessageId:3")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageDispatchTest.java new file mode 100644 index 0000000000..46067a5c0d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageDispatchTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageDispatch * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageDispatchTest extends BaseCommandTestSupport { public static MessageDispatchTest SINGLETON = new MessageDispatchTest(); public Object createObject() throws Exception { MessageDispatch info = new MessageDispatch(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageDispatch info = (MessageDispatch) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setMessage(createMessage("Message:3")); info.setRedeliveryCounter(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageIdTest.java new file mode 100644 index 0000000000..5be4923064 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageIdTest extends DataFileGeneratorTestSupport { public static MessageIdTest SINGLETON = new MessageIdTest(); public Object createObject() throws Exception { MessageId info = new MessageId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageId info = (MessageId) object; info.setProducerId(createProducerId("ProducerId:1")); info.setProducerSequenceId(1); info.setBrokerSequenceId(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessagePullTest.java new file mode 100644 index 0000000000..142224f665 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessagePullTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessagePull * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessagePullTest extends BaseCommandTestSupport { public static MessagePullTest SINGLETON = new MessagePullTest(); public Object createObject() throws Exception { MessagePull info = new MessagePull(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessagePull info = (MessagePull) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setTimeout(1); info.setCorrelationId("CorrelationId:3"); info.setMessageId(createMessageId("MessageId:4")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageTestSupport.java new file mode 100644 index 0000000000..0e3b269b50 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/MessageTestSupport.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for Message * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public abstract class MessageTestSupport extends BaseCommandTestSupport { protected void populateObject(Object object) throws Exception { super.populateObject(object); Message info = (Message) object; info.setProducerId(createProducerId("ProducerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setTransactionId(createTransactionId("TransactionId:3")); info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); info.setMessageId(createMessageId("MessageId:5")); info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); info.setGroupID("GroupID:7"); info.setGroupSequence(1); info.setCorrelationId("CorrelationId:8"); info.setPersistent(true); info.setExpiration(1); info.setPriority((byte) 1); info.setReplyTo(createActiveMQDestination("ReplyTo:9")); info.setTimestamp(2); info.setType("Type:10"); { byte data[] = "Content:11".getBytes(); info.setContent(new org.apache.activemq.util.ByteSequence(data,0,data.length)); } { byte data[] = "MarshalledProperties:12".getBytes(); info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data,0,data.length)); } info.setDataStructure(createDataStructure("DataStructure:13")); info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); info.setCompressed(false); info.setRedeliveryCounter(2); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:15"); } info.setBrokerPath(value); } info.setArrival(3); info.setUserID("UserID:16"); info.setRecievedByDFBridge(true); info.setDroppable(false); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("Cluster:17"); } info.setCluster(value); } info.setBrokerInTime(4); info.setBrokerOutTime(5); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..34d851b45a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/NetworkBridgeFilterTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for NetworkBridgeFilter * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { public static NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); public Object createObject() throws Exception { NetworkBridgeFilter info = new NetworkBridgeFilter(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); NetworkBridgeFilter info = (NetworkBridgeFilter) object; info.setNetworkTTL(1); info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/PartialCommandTest.java new file mode 100644 index 0000000000..30a22f8dba --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/PartialCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for PartialCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class PartialCommandTest extends DataFileGeneratorTestSupport { public static PartialCommandTest SINGLETON = new PartialCommandTest(); public Object createObject() throws Exception { PartialCommand info = new PartialCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); PartialCommand info = (PartialCommand) object; info.setCommandId(1); info.setData("Data:1".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerAckTest.java new file mode 100644 index 0000000000..d1296311e8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerAckTest extends BaseCommandTestSupport { public static ProducerAckTest SINGLETON = new ProducerAckTest(); public Object createObject() throws Exception { ProducerAck info = new ProducerAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerAck info = (ProducerAck) object; info.setProducerId(createProducerId("ProducerId:1")); info.setSize(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerIdTest.java new file mode 100644 index 0000000000..d61330bdb7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerIdTest extends DataFileGeneratorTestSupport { public static ProducerIdTest SINGLETON = new ProducerIdTest(); public Object createObject() throws Exception { ProducerId info = new ProducerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerId info = (ProducerId) object; info.setConnectionId("ConnectionId:1"); info.setValue(1); info.setSessionId(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerInfoTest.java new file mode 100644 index 0000000000..ba576c3468 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ProducerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerInfoTest extends BaseCommandTestSupport { public static ProducerInfoTest SINGLETON = new ProducerInfoTest(); public Object createObject() throws Exception { ProducerInfo info = new ProducerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerInfo info = (ProducerInfo) object; info.setProducerId(createProducerId("ProducerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:3"); } info.setBrokerPath(value); } info.setDispatchAsync(true); info.setWindowSize(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/RemoveInfoTest.java new file mode 100644 index 0000000000..0d5d5da9e6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/RemoveInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for RemoveInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class RemoveInfoTest extends BaseCommandTestSupport { public static RemoveInfoTest SINGLETON = new RemoveInfoTest(); public Object createObject() throws Exception { RemoveInfo info = new RemoveInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); RemoveInfo info = (RemoveInfo) object; info.setObjectId(createDataStructure("ObjectId:1")); info.setLastDeliveredSequenceId(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..9120790bc3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/RemoveSubscriptionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for RemoveSubscriptionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { public static RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); public Object createObject() throws Exception { RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setSubcriptionName("SubcriptionName:2"); info.setClientId("ClientId:3"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ReplayCommandTest.java new file mode 100644 index 0000000000..558edf77d5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ReplayCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ReplayCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ReplayCommandTest extends BaseCommandTestSupport { public static ReplayCommandTest SINGLETON = new ReplayCommandTest(); public Object createObject() throws Exception { ReplayCommand info = new ReplayCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ReplayCommand info = (ReplayCommand) object; info.setFirstNakNumber(1); info.setLastNakNumber(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ResponseTest.java new file mode 100644 index 0000000000..9a46fa0e18 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for Response * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ResponseTest extends BaseCommandTestSupport { public static ResponseTest SINGLETON = new ResponseTest(); public Object createObject() throws Exception { Response info = new Response(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); Response info = (Response) object; info.setCorrelationId(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SessionIdTest.java new file mode 100644 index 0000000000..ed13b5f0f0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SessionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SessionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SessionIdTest extends DataFileGeneratorTestSupport { public static SessionIdTest SINGLETON = new SessionIdTest(); public Object createObject() throws Exception { SessionId info = new SessionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SessionId info = (SessionId) object; info.setConnectionId("ConnectionId:1"); info.setValue(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SessionInfoTest.java new file mode 100644 index 0000000000..292e0efe66 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SessionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SessionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SessionInfoTest extends BaseCommandTestSupport { public static SessionInfoTest SINGLETON = new SessionInfoTest(); public Object createObject() throws Exception { SessionInfo info = new SessionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SessionInfo info = (SessionInfo) object; info.setSessionId(createSessionId("SessionId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ShutdownInfoTest.java new file mode 100644 index 0000000000..3bc212fa84 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/ShutdownInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ShutdownInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ShutdownInfoTest extends BaseCommandTestSupport { public static ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); public Object createObject() throws Exception { ShutdownInfo info = new ShutdownInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ShutdownInfo info = (ShutdownInfo) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SubscriptionInfoTest.java new file mode 100644 index 0000000000..a7179cf346 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/SubscriptionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SubscriptionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { public static SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); public Object createObject() throws Exception { SubscriptionInfo info = new SubscriptionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SubscriptionInfo info = (SubscriptionInfo) object; info.setClientId("ClientId:1"); info.setDestination(createActiveMQDestination("Destination:2")); info.setSelector("Selector:3"); info.setSubcriptionName("SubcriptionName:4"); info.setSubscribedDestination(createActiveMQDestination("SubscribedDestination:5")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/TransactionIdTestSupport.java new file mode 100644 index 0000000000..7781ea367c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/TransactionIdTestSupport.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for TransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { protected void populateObject(Object object) throws Exception { super.populateObject(object); TransactionId info = (TransactionId) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/TransactionInfoTest.java new file mode 100644 index 0000000000..53a11a508d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/TransactionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for TransactionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class TransactionInfoTest extends BaseCommandTestSupport { public static TransactionInfoTest SINGLETON = new TransactionInfoTest(); public Object createObject() throws Exception { TransactionInfo info = new TransactionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); TransactionInfo info = (TransactionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setTransactionId(createTransactionId("TransactionId:2")); info.setType((byte) 1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/XATransactionIdTest.java new file mode 100644 index 0000000000..0f7c2ebcee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v8/XATransactionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v8; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for XATransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class XATransactionIdTest extends TransactionIdTestSupport { public static XATransactionIdTest SINGLETON = new XATransactionIdTest(); public Object createObject() throws Exception { XATransactionId info = new XATransactionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); XATransactionId info = (XATransactionId) object; info.setFormatId(1); info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); info.setBranchQualifier("BranchQualifier:2".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BaseCommandTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BaseCommandTestSupport.java new file mode 100644 index 0000000000..c11b7f4c91 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BaseCommandTestSupport.java @@ -0,0 +1,38 @@ +/** + * 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.openwire.v9; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.openwire.DataFileGeneratorTestSupport; + +/** + * Test case for the OpenWire marshalling for BaseCommand NOTE!: This file is + * auto generated - do not modify! if you need to make a change, please see the + * modify the groovy scripts in the under src/gram/script and then use maven + * openwire:generate to regenerate this file. + * + */ +public abstract class BaseCommandTestSupport extends DataFileGeneratorTestSupport { + + protected void populateObject(Object object) throws Exception { + super.populateObject(object); + BaseCommand info = (BaseCommand)object; + info.setCommandId(1); + info.setResponseRequired(true); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BrokerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BrokerIdTest.java new file mode 100644 index 0000000000..0d53067e80 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BrokerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for BrokerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class BrokerIdTest extends DataFileGeneratorTestSupport { public static BrokerIdTest SINGLETON = new BrokerIdTest(); public Object createObject() throws Exception { BrokerId info = new BrokerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); BrokerId info = (BrokerId) object; info.setValue("Value:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BrokerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BrokerInfoTest.java new file mode 100644 index 0000000000..b0d9658922 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/BrokerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for BrokerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class BrokerInfoTest extends BaseCommandTestSupport { public static BrokerInfoTest SINGLETON = new BrokerInfoTest(); public Object createObject() throws Exception { BrokerInfo info = new BrokerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); BrokerInfo info = (BrokerInfo) object; info.setBrokerId(createBrokerId("BrokerId:1")); info.setBrokerURL("BrokerURL:2"); { BrokerInfo value[] = new BrokerInfo[0]; for( int i=0; i < 0; i++ ) { value[i] = createBrokerInfo("PeerBrokerInfos:3"); } info.setPeerBrokerInfos(value); } info.setBrokerName("BrokerName:4"); info.setSlaveBroker(true); info.setMasterBroker(false); info.setFaultTolerantConfiguration(true); info.setDuplexConnection(false); info.setNetworkConnection(true); info.setConnectionId(1); info.setBrokerUploadUrl("BrokerUploadUrl:5"); info.setNetworkProperties("NetworkProperties:6"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionControlTest.java new file mode 100644 index 0000000000..e259ec7904 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionControlTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionControl * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionControlTest extends BaseCommandTestSupport { public static ConnectionControlTest SINGLETON = new ConnectionControlTest(); public Object createObject() throws Exception { ConnectionControl info = new ConnectionControl(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionControl info = (ConnectionControl) object; info.setClose(true); info.setExit(false); info.setFaultTolerant(true); info.setResume(false); info.setSuspend(true); info.setConnectedBrokers("ConnectedBrokers:1"); info.setReconnectTo("ReconnectTo:2"); info.setRebalanceConnection(false); info.setToken("Token:3".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionErrorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionErrorTest.java new file mode 100644 index 0000000000..52ce46b917 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionErrorTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionError * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionErrorTest extends BaseCommandTestSupport { public static ConnectionErrorTest SINGLETON = new ConnectionErrorTest(); public Object createObject() throws Exception { ConnectionError info = new ConnectionError(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionError info = (ConnectionError) object; info.setException(createThrowable("Exception:1")); info.setConnectionId(createConnectionId("ConnectionId:2")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionIdTest.java new file mode 100644 index 0000000000..d0b4fcfe3d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionIdTest extends DataFileGeneratorTestSupport { public static ConnectionIdTest SINGLETON = new ConnectionIdTest(); public Object createObject() throws Exception { ConnectionId info = new ConnectionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionId info = (ConnectionId) object; info.setValue("Value:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionInfoTest.java new file mode 100644 index 0000000000..9cafabc29b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConnectionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConnectionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConnectionInfoTest extends BaseCommandTestSupport { public static ConnectionInfoTest SINGLETON = new ConnectionInfoTest(); public Object createObject() throws Exception { ConnectionInfo info = new ConnectionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConnectionInfo info = (ConnectionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setClientId("ClientId:2"); info.setPassword("Password:3"); info.setUserName("UserName:4"); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:5"); } info.setBrokerPath(value); } info.setBrokerMasterConnector(true); info.setManageable(false); info.setClientMaster(true); info.setFaultTolerant(false); info.setFailoverReconnect(true); info.setClientIp("ClientIp:6"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerControlTest.java new file mode 100644 index 0000000000..39fc381516 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerControlTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerControl * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerControlTest extends BaseCommandTestSupport { public static ConsumerControlTest SINGLETON = new ConsumerControlTest(); public Object createObject() throws Exception { ConsumerControl info = new ConsumerControl(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerControl info = (ConsumerControl) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setClose(true); info.setConsumerId(createConsumerId("ConsumerId:2")); info.setPrefetch(1); info.setFlush(false); info.setStart(true); info.setStop(false); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerIdTest.java new file mode 100644 index 0000000000..edefe398c2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerIdTest extends DataFileGeneratorTestSupport { public static ConsumerIdTest SINGLETON = new ConsumerIdTest(); public Object createObject() throws Exception { ConsumerId info = new ConsumerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerId info = (ConsumerId) object; info.setConnectionId("ConnectionId:1"); info.setSessionId(1); info.setValue(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerInfoTest.java new file mode 100644 index 0000000000..a31ff687a3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ConsumerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ConsumerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ConsumerInfoTest extends BaseCommandTestSupport { public static ConsumerInfoTest SINGLETON = new ConsumerInfoTest(); public Object createObject() throws Exception { ConsumerInfo info = new ConsumerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ConsumerInfo info = (ConsumerInfo) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setBrowser(true); info.setDestination(createActiveMQDestination("Destination:2")); info.setPrefetchSize(1); info.setMaximumPendingMessageLimit(2); info.setDispatchAsync(false); info.setSelector("Selector:3"); info.setSubscriptionName("SubscriptionName:4"); info.setNoLocal(true); info.setExclusive(false); info.setRetroactive(true); info.setPriority((byte) 1); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:5"); } info.setBrokerPath(value); } info.setAdditionalPredicate(createBooleanExpression("AdditionalPredicate:6")); info.setNetworkSubscription(false); info.setOptimizedAcknowledge(true); info.setNoRangeAcks(false); { ConsumerId value[] = new ConsumerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createConsumerId("NetworkConsumerPath:7"); } info.setNetworkConsumerPath(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ControlCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ControlCommandTest.java new file mode 100644 index 0000000000..6e86e3c594 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ControlCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ControlCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ControlCommandTest extends BaseCommandTestSupport { public static ControlCommandTest SINGLETON = new ControlCommandTest(); public Object createObject() throws Exception { ControlCommand info = new ControlCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ControlCommand info = (ControlCommand) object; info.setCommand("Command:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DataArrayResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DataArrayResponseTest.java new file mode 100644 index 0000000000..967964a461 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DataArrayResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DataArrayResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DataArrayResponseTest extends ResponseTest { public static DataArrayResponseTest SINGLETON = new DataArrayResponseTest(); public Object createObject() throws Exception { DataArrayResponse info = new DataArrayResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DataArrayResponse info = (DataArrayResponse) object; { DataStructure value[] = new DataStructure[2]; for( int i=0; i < 2; i++ ) { value[i] = createDataStructure("Data:1"); } info.setData(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DataResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DataResponseTest.java new file mode 100644 index 0000000000..82014879dd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DataResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DataResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DataResponseTest extends ResponseTest { public static DataResponseTest SINGLETON = new DataResponseTest(); public Object createObject() throws Exception { DataResponse info = new DataResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DataResponse info = (DataResponse) object; info.setData(createDataStructure("Data:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DestinationInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DestinationInfoTest.java new file mode 100644 index 0000000000..35d8298be4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DestinationInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DestinationInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DestinationInfoTest extends BaseCommandTestSupport { public static DestinationInfoTest SINGLETON = new DestinationInfoTest(); public Object createObject() throws Exception { DestinationInfo info = new DestinationInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DestinationInfo info = (DestinationInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setOperationType((byte) 1); info.setTimeout(1); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:3"); } info.setBrokerPath(value); } } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DiscoveryEventTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DiscoveryEventTest.java new file mode 100644 index 0000000000..e2709d7d00 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/DiscoveryEventTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for DiscoveryEvent * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class DiscoveryEventTest extends DataFileGeneratorTestSupport { public static DiscoveryEventTest SINGLETON = new DiscoveryEventTest(); public Object createObject() throws Exception { DiscoveryEvent info = new DiscoveryEvent(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); DiscoveryEvent info = (DiscoveryEvent) object; info.setServiceName("ServiceName:1"); info.setBrokerName("BrokerName:2"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ExceptionResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ExceptionResponseTest.java new file mode 100644 index 0000000000..27b56cad26 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ExceptionResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ExceptionResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ExceptionResponseTest extends ResponseTest { public static ExceptionResponseTest SINGLETON = new ExceptionResponseTest(); public Object createObject() throws Exception { ExceptionResponse info = new ExceptionResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ExceptionResponse info = (ExceptionResponse) object; info.setException(createThrowable("Exception:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/FlushCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/FlushCommandTest.java new file mode 100644 index 0000000000..e6fec771cd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/FlushCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for FlushCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class FlushCommandTest extends BaseCommandTestSupport { public static FlushCommandTest SINGLETON = new FlushCommandTest(); public Object createObject() throws Exception { FlushCommand info = new FlushCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); FlushCommand info = (FlushCommand) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/IntegerResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/IntegerResponseTest.java new file mode 100644 index 0000000000..08b844a85d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/IntegerResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for IntegerResponse * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class IntegerResponseTest extends ResponseTest { public static IntegerResponseTest SINGLETON = new IntegerResponseTest(); public Object createObject() throws Exception { IntegerResponse info = new IntegerResponse(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); IntegerResponse info = (IntegerResponse) object; info.setResult(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalQueueAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalQueueAckTest.java new file mode 100644 index 0000000000..15bc4e1a89 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalQueueAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalQueueAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalQueueAckTest extends DataFileGeneratorTestSupport { public static JournalQueueAckTest SINGLETON = new JournalQueueAckTest(); public Object createObject() throws Exception { JournalQueueAck info = new JournalQueueAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalQueueAck info = (JournalQueueAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setMessageAck(createMessageAck("MessageAck:2")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTopicAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTopicAckTest.java new file mode 100644 index 0000000000..92ee5fce40 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTopicAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTopicAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTopicAckTest extends DataFileGeneratorTestSupport { public static JournalTopicAckTest SINGLETON = new JournalTopicAckTest(); public Object createObject() throws Exception { JournalTopicAck info = new JournalTopicAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTopicAck info = (JournalTopicAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setMessageId(createMessageId("MessageId:2")); info.setMessageSequenceId(1); info.setSubscritionName("SubscritionName:3"); info.setClientId("ClientId:4"); info.setTransactionId(createTransactionId("TransactionId:5")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTraceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTraceTest.java new file mode 100644 index 0000000000..fedee00cd1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTraceTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTrace * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTraceTest extends DataFileGeneratorTestSupport { public static JournalTraceTest SINGLETON = new JournalTraceTest(); public Object createObject() throws Exception { JournalTrace info = new JournalTrace(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTrace info = (JournalTrace) object; info.setMessage("Message:1"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTransactionTest.java new file mode 100644 index 0000000000..ffad3dc019 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/JournalTransactionTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for JournalTransaction * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class JournalTransactionTest extends DataFileGeneratorTestSupport { public static JournalTransactionTest SINGLETON = new JournalTransactionTest(); public Object createObject() throws Exception { JournalTransaction info = new JournalTransaction(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); JournalTransaction info = (JournalTransaction) object; info.setTransactionId(createTransactionId("TransactionId:1")); info.setType((byte) 1); info.setWasPrepared(true); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/KeepAliveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/KeepAliveInfoTest.java new file mode 100644 index 0000000000..aa04459bb7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/KeepAliveInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for KeepAliveInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class KeepAliveInfoTest extends BaseCommandTestSupport { public static KeepAliveInfoTest SINGLETON = new KeepAliveInfoTest(); public Object createObject() throws Exception { KeepAliveInfo info = new KeepAliveInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); KeepAliveInfo info = (KeepAliveInfo) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/LastPartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/LastPartialCommandTest.java new file mode 100644 index 0000000000..6073a93311 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/LastPartialCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for LastPartialCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class LastPartialCommandTest extends PartialCommandTest { public static LastPartialCommandTest SINGLETON = new LastPartialCommandTest(); public Object createObject() throws Exception { LastPartialCommand info = new LastPartialCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); LastPartialCommand info = (LastPartialCommand) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/LocalTransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/LocalTransactionIdTest.java new file mode 100644 index 0000000000..92fde53172 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/LocalTransactionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for LocalTransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class LocalTransactionIdTest extends TransactionIdTestSupport { public static LocalTransactionIdTest SINGLETON = new LocalTransactionIdTest(); public Object createObject() throws Exception { LocalTransactionId info = new LocalTransactionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); LocalTransactionId info = (LocalTransactionId) object; info.setValue(1); info.setConnectionId(createConnectionId("ConnectionId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageAckTest.java new file mode 100644 index 0000000000..975042f2f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageAckTest extends BaseCommandTestSupport { public static MessageAckTest SINGLETON = new MessageAckTest(); public Object createObject() throws Exception { MessageAck info = new MessageAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageAck info = (MessageAck) object; info.setDestination(createActiveMQDestination("Destination:1")); info.setTransactionId(createTransactionId("TransactionId:2")); info.setConsumerId(createConsumerId("ConsumerId:3")); info.setAckType((byte) 1); info.setFirstMessageId(createMessageId("FirstMessageId:4")); info.setLastMessageId(createMessageId("LastMessageId:5")); info.setMessageCount(1); info.setPoisonCause(createThrowable("PoisonCause:6")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageDispatchNotificationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageDispatchNotificationTest.java new file mode 100644 index 0000000000..d335b0bbea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageDispatchNotificationTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageDispatchNotification * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageDispatchNotificationTest extends BaseCommandTestSupport { public static MessageDispatchNotificationTest SINGLETON = new MessageDispatchNotificationTest(); public Object createObject() throws Exception { MessageDispatchNotification info = new MessageDispatchNotification(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageDispatchNotification info = (MessageDispatchNotification) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setDeliverySequenceId(1); info.setMessageId(createMessageId("MessageId:3")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageDispatchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageDispatchTest.java new file mode 100644 index 0000000000..38fb0dc0a1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageDispatchTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageDispatch * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageDispatchTest extends BaseCommandTestSupport { public static MessageDispatchTest SINGLETON = new MessageDispatchTest(); public Object createObject() throws Exception { MessageDispatch info = new MessageDispatch(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageDispatch info = (MessageDispatch) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setMessage(createMessage("Message:3")); info.setRedeliveryCounter(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageIdTest.java new file mode 100644 index 0000000000..d64c66e1c0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessageId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessageIdTest extends DataFileGeneratorTestSupport { public static MessageIdTest SINGLETON = new MessageIdTest(); public Object createObject() throws Exception { MessageId info = new MessageId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessageId info = (MessageId) object; info.setProducerId(createProducerId("ProducerId:1")); info.setProducerSequenceId(1); info.setBrokerSequenceId(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessagePullTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessagePullTest.java new file mode 100644 index 0000000000..55af8b1a3f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessagePullTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for MessagePull * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class MessagePullTest extends BaseCommandTestSupport { public static MessagePullTest SINGLETON = new MessagePullTest(); public Object createObject() throws Exception { MessagePull info = new MessagePull(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); MessagePull info = (MessagePull) object; info.setConsumerId(createConsumerId("ConsumerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setTimeout(1); info.setCorrelationId("CorrelationId:3"); info.setMessageId(createMessageId("MessageId:4")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageTestSupport.java new file mode 100644 index 0000000000..3557528dee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/MessageTestSupport.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for Message * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public abstract class MessageTestSupport extends BaseCommandTestSupport { protected void populateObject(Object object) throws Exception { super.populateObject(object); Message info = (Message) object; info.setProducerId(createProducerId("ProducerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); info.setTransactionId(createTransactionId("TransactionId:3")); info.setOriginalDestination(createActiveMQDestination("OriginalDestination:4")); info.setMessageId(createMessageId("MessageId:5")); info.setOriginalTransactionId(createTransactionId("OriginalTransactionId:6")); info.setGroupID("GroupID:7"); info.setGroupSequence(1); info.setCorrelationId("CorrelationId:8"); info.setPersistent(true); info.setExpiration(1); info.setPriority((byte) 1); info.setReplyTo(createActiveMQDestination("ReplyTo:9")); info.setTimestamp(2); info.setType("Type:10"); { byte data[] = "Content:11".getBytes(); info.setContent(new org.apache.activemq.util.ByteSequence(data,0,data.length)); } { byte data[] = "MarshalledProperties:12".getBytes(); info.setMarshalledProperties(new org.apache.activemq.util.ByteSequence(data,0,data.length)); } info.setDataStructure(createDataStructure("DataStructure:13")); info.setTargetConsumerId(createConsumerId("TargetConsumerId:14")); info.setCompressed(false); info.setRedeliveryCounter(2); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:15"); } info.setBrokerPath(value); } info.setArrival(3); info.setUserID("UserID:16"); info.setRecievedByDFBridge(true); info.setDroppable(false); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("Cluster:17"); } info.setCluster(value); } info.setBrokerInTime(4); info.setBrokerOutTime(5); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/NetworkBridgeFilterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/NetworkBridgeFilterTest.java new file mode 100644 index 0000000000..9b9c501109 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/NetworkBridgeFilterTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for NetworkBridgeFilter * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class NetworkBridgeFilterTest extends DataFileGeneratorTestSupport { public static NetworkBridgeFilterTest SINGLETON = new NetworkBridgeFilterTest(); public Object createObject() throws Exception { NetworkBridgeFilter info = new NetworkBridgeFilter(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); NetworkBridgeFilter info = (NetworkBridgeFilter) object; info.setNetworkTTL(1); info.setNetworkBrokerId(createBrokerId("NetworkBrokerId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/PartialCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/PartialCommandTest.java new file mode 100644 index 0000000000..f79e06716a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/PartialCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for PartialCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class PartialCommandTest extends DataFileGeneratorTestSupport { public static PartialCommandTest SINGLETON = new PartialCommandTest(); public Object createObject() throws Exception { PartialCommand info = new PartialCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); PartialCommand info = (PartialCommand) object; info.setCommandId(1); info.setData("Data:1".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerAckTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerAckTest.java new file mode 100644 index 0000000000..226a8f8fae --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerAckTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerAck * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerAckTest extends BaseCommandTestSupport { public static ProducerAckTest SINGLETON = new ProducerAckTest(); public Object createObject() throws Exception { ProducerAck info = new ProducerAck(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerAck info = (ProducerAck) object; info.setProducerId(createProducerId("ProducerId:1")); info.setSize(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerIdTest.java new file mode 100644 index 0000000000..72d7e35a24 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerIdTest extends DataFileGeneratorTestSupport { public static ProducerIdTest SINGLETON = new ProducerIdTest(); public Object createObject() throws Exception { ProducerId info = new ProducerId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerId info = (ProducerId) object; info.setConnectionId("ConnectionId:1"); info.setValue(1); info.setSessionId(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerInfoTest.java new file mode 100644 index 0000000000..131c478075 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ProducerInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ProducerInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ProducerInfoTest extends BaseCommandTestSupport { public static ProducerInfoTest SINGLETON = new ProducerInfoTest(); public Object createObject() throws Exception { ProducerInfo info = new ProducerInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ProducerInfo info = (ProducerInfo) object; info.setProducerId(createProducerId("ProducerId:1")); info.setDestination(createActiveMQDestination("Destination:2")); { BrokerId value[] = new BrokerId[2]; for( int i=0; i < 2; i++ ) { value[i] = createBrokerId("BrokerPath:3"); } info.setBrokerPath(value); } info.setDispatchAsync(true); info.setWindowSize(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/RemoveInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/RemoveInfoTest.java new file mode 100644 index 0000000000..de9b5cd2b4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/RemoveInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for RemoveInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class RemoveInfoTest extends BaseCommandTestSupport { public static RemoveInfoTest SINGLETON = new RemoveInfoTest(); public Object createObject() throws Exception { RemoveInfo info = new RemoveInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); RemoveInfo info = (RemoveInfo) object; info.setObjectId(createDataStructure("ObjectId:1")); info.setLastDeliveredSequenceId(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/RemoveSubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/RemoveSubscriptionInfoTest.java new file mode 100644 index 0000000000..9683e33f53 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/RemoveSubscriptionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for RemoveSubscriptionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class RemoveSubscriptionInfoTest extends BaseCommandTestSupport { public static RemoveSubscriptionInfoTest SINGLETON = new RemoveSubscriptionInfoTest(); public Object createObject() throws Exception { RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); RemoveSubscriptionInfo info = (RemoveSubscriptionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setSubcriptionName("SubcriptionName:2"); info.setClientId("ClientId:3"); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ReplayCommandTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ReplayCommandTest.java new file mode 100644 index 0000000000..22ede48c93 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ReplayCommandTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ReplayCommand * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ReplayCommandTest extends BaseCommandTestSupport { public static ReplayCommandTest SINGLETON = new ReplayCommandTest(); public Object createObject() throws Exception { ReplayCommand info = new ReplayCommand(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ReplayCommand info = (ReplayCommand) object; info.setFirstNakNumber(1); info.setLastNakNumber(2); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ResponseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ResponseTest.java new file mode 100644 index 0000000000..97bb45c5d3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ResponseTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for Response * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ResponseTest extends BaseCommandTestSupport { public static ResponseTest SINGLETON = new ResponseTest(); public Object createObject() throws Exception { Response info = new Response(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); Response info = (Response) object; info.setCorrelationId(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SessionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SessionIdTest.java new file mode 100644 index 0000000000..9d71dd57fe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SessionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SessionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SessionIdTest extends DataFileGeneratorTestSupport { public static SessionIdTest SINGLETON = new SessionIdTest(); public Object createObject() throws Exception { SessionId info = new SessionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SessionId info = (SessionId) object; info.setConnectionId("ConnectionId:1"); info.setValue(1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SessionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SessionInfoTest.java new file mode 100644 index 0000000000..938296abf8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SessionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SessionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SessionInfoTest extends BaseCommandTestSupport { public static SessionInfoTest SINGLETON = new SessionInfoTest(); public Object createObject() throws Exception { SessionInfo info = new SessionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SessionInfo info = (SessionInfo) object; info.setSessionId(createSessionId("SessionId:1")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ShutdownInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ShutdownInfoTest.java new file mode 100644 index 0000000000..be4b398e29 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/ShutdownInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for ShutdownInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class ShutdownInfoTest extends BaseCommandTestSupport { public static ShutdownInfoTest SINGLETON = new ShutdownInfoTest(); public Object createObject() throws Exception { ShutdownInfo info = new ShutdownInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); ShutdownInfo info = (ShutdownInfo) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SubscriptionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SubscriptionInfoTest.java new file mode 100644 index 0000000000..3366769010 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/SubscriptionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for SubscriptionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class SubscriptionInfoTest extends DataFileGeneratorTestSupport { public static SubscriptionInfoTest SINGLETON = new SubscriptionInfoTest(); public Object createObject() throws Exception { SubscriptionInfo info = new SubscriptionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); SubscriptionInfo info = (SubscriptionInfo) object; info.setClientId("ClientId:1"); info.setDestination(createActiveMQDestination("Destination:2")); info.setSelector("Selector:3"); info.setSubcriptionName("SubcriptionName:4"); info.setSubscribedDestination(createActiveMQDestination("SubscribedDestination:5")); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/TransactionIdTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/TransactionIdTestSupport.java new file mode 100644 index 0000000000..3f61dcece4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/TransactionIdTestSupport.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for TransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public abstract class TransactionIdTestSupport extends DataFileGeneratorTestSupport { protected void populateObject(Object object) throws Exception { super.populateObject(object); TransactionId info = (TransactionId) object; } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/TransactionInfoTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/TransactionInfoTest.java new file mode 100644 index 0000000000..d08dd818f6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/TransactionInfoTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for TransactionInfo * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class TransactionInfoTest extends BaseCommandTestSupport { public static TransactionInfoTest SINGLETON = new TransactionInfoTest(); public Object createObject() throws Exception { TransactionInfo info = new TransactionInfo(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); TransactionInfo info = (TransactionInfo) object; info.setConnectionId(createConnectionId("ConnectionId:1")); info.setTransactionId(createTransactionId("TransactionId:2")); info.setType((byte) 1); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/XATransactionIdTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/XATransactionIdTest.java new file mode 100644 index 0000000000..f73711ea27 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/openwire/v9/XATransactionIdTest.java @@ -0,0 +1 @@ +/** * * 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.openwire.v9; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.activemq.openwire.*; import org.apache.activemq.command.*; /** * Test case for the OpenWire marshalling for XATransactionId * * * NOTE!: This file is auto generated - do not modify! * if you need to make a change, please see the modify the groovy scripts in the * under src/gram/script and then use maven openwire:generate to regenerate * this file. * * */ public class XATransactionIdTest extends TransactionIdTestSupport { public static XATransactionIdTest SINGLETON = new XATransactionIdTest(); public Object createObject() throws Exception { XATransactionId info = new XATransactionId(); populateObject(info); return info; } protected void populateObject(Object object) throws Exception { super.populateObject(object); XATransactionId info = (XATransactionId) object; info.setFormatId(1); info.setGlobalTransactionId("GlobalTransactionId:1".getBytes()); info.setBranchQualifier("BranchQualifier:2".getBytes()); } } \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/ConnectionChurnTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/ConnectionChurnTest.java new file mode 100644 index 0000000000..2e2402d178 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/ConnectionChurnTest.java @@ -0,0 +1,105 @@ +/** + * 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.perf; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ConnectionChurnTest extends TestCase { + protected static final int CONNECTION_COUNT = 200; + private static final Logger LOG = LoggerFactory.getLogger(ConnectionChurnTest.class); + protected BrokerService broker; + protected String bindAddress = ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL+"?transport.closeAsync=false"; + protected int topicCount; + + public void testPerformance() throws Exception { + ConnectionFactory factory = createConnectionFactory(); + List list = new ArrayList(); + for (int i = 0; i < CONNECTION_COUNT; i++) { + Connection connection = factory.createConnection(); + connection.start(); + list.add(connection); + LOG.info("Created " + i); + if (i % 100 == 0) { + closeConnections(list); + } + } + closeConnections(list); + } + + protected void closeConnections(List list) throws JMSException { + for (Connection c : list) { + c.close(); + } + for (TransportConnector tc : broker.getTransportConnectors()) { + System.out.println(tc.getConnections().size()); + } + list.clear(); + } + + @Override + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() + throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory( + ActiveMQConnection.DEFAULT_BROKER_URL); + return cf; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.setPersistent(false); + answer.addConnector(bindAddress); + answer.setDeleteAllMessagesOnStartup(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/InactiveDurableTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/InactiveDurableTopicTest.java new file mode 100644 index 0000000000..9ab45b99bd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/InactiveDurableTopicTest.java @@ -0,0 +1,190 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class InactiveDurableTopicTest extends TestCase { + private static final transient Logger LOG = LoggerFactory.getLogger(InactiveDurableTopicTest.class); + + private static final int MESSAGE_COUNT = 2000; + private static final String DEFAULT_PASSWORD = ""; + private static final String USERNAME = "testuser"; + private static final String CLIENTID = "mytestclient"; + private static final String TOPIC_NAME = "testevent"; + private static final String SUBID = "subscription1"; + private static final int DELIVERY_MODE = javax.jms.DeliveryMode.PERSISTENT; + private static final int DELIVERY_PRIORITY = javax.jms.Message.DEFAULT_PRIORITY; + private Connection connection; + private MessageProducer publisher; + private TopicSubscriber subscriber; + private Topic topic; + private Session session; + private ActiveMQConnectionFactory connectionFactory; + private BrokerService broker; + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + + //broker.setPersistenceAdapter(new KahaPersistenceAdapter()); + /* + * JournalPersistenceAdapterFactory factory = new + * JournalPersistenceAdapterFactory(); + * factory.setDataDirectoryFile(broker.getDataDirectory()); + * factory.setTaskRunnerFactory(broker.getTaskRunnerFactory()); + * factory.setUseJournal(false); broker.setPersistenceFactory(factory); + */ + broker.addConnector(ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL); + broker.start(); + connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnectionFactory.DEFAULT_BROKER_URL); + /* + * Doesn't matter if you enable or disable these, so just leaving them + * out for this test case connectionFactory.setAlwaysSessionAsync(true); + * connectionFactory.setAsyncDispatch(true); + */ + connectionFactory.setUseAsyncSend(true); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + broker.stop(); + } + + public void test1CreateSubscription() throws Exception { + try { + /* + * Step 1 - Establish a connection with a client id and create a + * durable subscription + */ + connection = connectionFactory.createConnection(USERNAME, DEFAULT_PASSWORD); + assertNotNull(connection); + connection.setClientID(CLIENTID); + connection.start(); + session = connection.createSession(false, javax.jms.Session.CLIENT_ACKNOWLEDGE); + assertNotNull(session); + topic = session.createTopic(TOPIC_NAME); + assertNotNull(topic); + subscriber = session.createDurableSubscriber(topic, SUBID, "", false); + assertNotNull(subscriber); + subscriber.close(); + session.close(); + connection.close(); + } catch (JMSException ex) { + try { + connection.close(); + } catch (Exception ignore) { + } + throw new AssertionFailedError("Create Subscription caught: " + ex); + } + } + + public void test2ProducerTestCase() { + /* + * Step 2 - Establish a connection without a client id and create a + * producer and start pumping messages. We will get hung + */ + try { + connection = connectionFactory.createConnection(USERNAME, DEFAULT_PASSWORD); + assertNotNull(connection); + session = connection.createSession(false, javax.jms.Session.CLIENT_ACKNOWLEDGE); + assertNotNull(session); + topic = session.createTopic(TOPIC_NAME); + assertNotNull(topic); + publisher = session.createProducer(topic); + assertNotNull(publisher); + MapMessage msg = session.createMapMessage(); + assertNotNull(msg); + msg.setString("key1", "value1"); + int loop; + for (loop = 0; loop < MESSAGE_COUNT; loop++) { + msg.setInt("key2", loop); + publisher.send(msg, DELIVERY_MODE, DELIVERY_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + if (loop % 5000 == 0) { + LOG.info("Sent " + loop + " messages"); + } + } + assertEquals(loop, MESSAGE_COUNT); + publisher.close(); + session.close(); + connection.stop(); + connection.stop(); + } catch (JMSException ex) { + try { + connection.close(); + } catch (Exception ignore) { + } + throw new AssertionFailedError("Create Subscription caught: " + ex); + } + } + + public void test3CreateSubscription() throws Exception { + try { + /* + * Step 1 - Establish a connection with a client id and create a + * durable subscription + */ + connection = connectionFactory.createConnection(USERNAME, DEFAULT_PASSWORD); + assertNotNull(connection); + connection.setClientID(CLIENTID); + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + assertNotNull(session); + topic = session.createTopic(TOPIC_NAME); + assertNotNull(topic); + subscriber = session.createDurableSubscriber(topic, SUBID, "", false); + assertNotNull(subscriber); + int loop; + for (loop = 0; loop < MESSAGE_COUNT; loop++) { + subscriber.receive(); + if (loop % 500 == 0) { + LOG.debug("Received " + loop + " messages"); + } + } + assertEquals(loop, MESSAGE_COUNT); + subscriber.close(); + session.close(); + connection.close(); + } catch (JMSException ex) { + try { + connection.close(); + } catch (Exception ignore) { + } + throw new AssertionFailedError("Create Subscription caught: " + ex); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/InactiveQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/InactiveQueueTest.java new file mode 100644 index 0000000000..866926233d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/InactiveQueueTest.java @@ -0,0 +1,114 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class InactiveQueueTest extends TestCase { + private static final transient Logger LOG = LoggerFactory.getLogger(InactiveQueueTest.class); + + private static final int MESSAGE_COUNT = 0; + private static final String DEFAULT_PASSWORD = ""; + private static final String USERNAME = "testuser"; + private static final String QUEUE_NAME = "testevent"; + private static final int DELIVERY_MODE = javax.jms.DeliveryMode.PERSISTENT; + private static final int DELIVERY_PRIORITY = javax.jms.Message.DEFAULT_PRIORITY; + + ActiveMQConnectionFactory connectionFactory; + BrokerService broker; + + private Connection connection; + private MessageProducer publisher; + private Destination destination; + private Session session; + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + + // broker.setPersistenceAdapter(new KahaPersistenceAdapter(new File + // ("TEST_STUFD"))); + /* + * JournalPersistenceAdapterFactory factory = new + * JournalPersistenceAdapterFactory(); + * factory.setDataDirectoryFile(broker.getDataDirectory()); + * factory.setTaskRunnerFactory(broker.getTaskRunnerFactory()); + * factory.setUseJournal(false); broker.setPersistenceFactory(factory); + */ + broker.addConnector(ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL); + broker.start(); + connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnectionFactory.DEFAULT_BROKER_URL); + /* + * Doesn't matter if you enable or disable these, so just leaving them + * out for this test case connectionFactory.setAlwaysSessionAsync(true); + * connectionFactory.setAsyncDispatch(true); + */ + connectionFactory.setUseAsyncSend(true); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + broker.stop(); + } + + public void testNoSubscribers() throws Exception { + connection = connectionFactory.createConnection(USERNAME, DEFAULT_PASSWORD); + assertNotNull(connection); + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + assertNotNull(session); + destination = session.createQueue(QUEUE_NAME); + assertNotNull(destination); + publisher = session.createProducer(destination); + assertNotNull(publisher); + MapMessage msg = session.createMapMessage(); + assertNotNull(msg); + msg.setString("key1", "value1"); + int loop; + for (loop = 0; loop < MESSAGE_COUNT; loop++) { + msg.setInt("key2", loop); + publisher.send(msg, DELIVERY_MODE, DELIVERY_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + if (loop % 500 == 0) { + LOG.debug("Sent " + loop + " messages"); + } + } + Thread.sleep(1000000); + assertEquals(loop, MESSAGE_COUNT); + publisher.close(); + session.close(); + connection.stop(); + connection.stop(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBDurableTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBDurableTopicTest.java new file mode 100644 index 0000000000..3609c62879 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBDurableTopicTest.java @@ -0,0 +1,52 @@ +/** + * 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.perf; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; + +/** + * + */ +public class KahaDBDurableTopicTest extends SimpleDurableTopicTest { + + @Override + protected void setUp() throws Exception { + //this.initialConsumerDelay = 10 * 1000; + super.setUp(); + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory(String uri) throws Exception { + ActiveMQConnectionFactory result = new ActiveMQConnectionFactory(uri); + //result.setDispatchAsync(false); + return result; + } + + @Override + protected void configureBroker(BrokerService answer,String uri) throws Exception { + //AMQPersistenceAdapterFactory persistenceFactory = new AMQPersistenceAdapterFactory(); + //persistenceFactory.setMaxFileLength(1024*16); + //persistenceFactory.setPersistentIndex(true); + //persistenceFactory.setCleanupInterval(10000); + //answer.setPersistenceFactory(persistenceFactory); + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(uri); + answer.setUseShutdownHook(false); + answer.setEnableStatistics(false); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBDurableTransactedTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBDurableTransactedTopicTest.java new file mode 100644 index 0000000000..d1ed9cffd4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBDurableTransactedTopicTest.java @@ -0,0 +1,42 @@ +/** + * 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.perf; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; + +/** + * + */ +public class KahaDBDurableTransactedTopicTest extends KahaDBDurableTopicTest { + + @Override + protected void setUp() throws Exception { + //this.initialConsumerDelay = 10 * 1000; + super.setUp(); + } + @Override + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte[] payload) throws JMSException { + PerfProducer result= new PerfProducer(fac, dest, payload, true); + result.setDeliveryMode(DeliveryMode.PERSISTENT); + return result; + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBQueueTest.java new file mode 100644 index 0000000000..a11b92e3c0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaDBQueueTest.java @@ -0,0 +1,63 @@ +/** + * 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.perf; + +import java.io.File; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; + +/** + * + */ +public class KahaDBQueueTest extends SimpleQueueTest { + + @Override + protected void setUp() throws Exception { + this.numberOfDestinations = 25; + this.numberofProducers = 1; + super.setUp(); + } + @Override + protected void configureBroker(BrokerService answer,String uri) throws Exception { + + File dataFileDir = new File("target/test-amq-data/perfTest/kahadb"); + File archiveDir = new File(dataFileDir,"archive"); + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setDirectory(dataFileDir); + kaha.setDirectoryArchive(archiveDir); + kaha.setArchiveDataLogs(false); + + // The setEnableJournalDiskSyncs(false) setting is a little dangerous right now, as I have not verified + // what happens if the index is updated but a journal update is lost. + // Index is going to be in consistent, but can it be repaired? + kaha.setEnableJournalDiskSyncs(true); + // Using a bigger journal file size makes he take fewer spikes as it is not switching files as often. + //kaha.setJournalMaxFileLength(1024*1024*100); + + // small batch means more frequent and smaller writes + //kaha.setIndexWriteBatchSize(100); + // do the index write in a separate thread + kaha.setEnableIndexWriteAsync(true); + kaha.setIndexCacheSize(10000); + + answer.setPersistenceAdapter(kaha); + answer.addConnector(uri); + answer.setDeleteAllMessagesOnStartup(true); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaQueueTest.java new file mode 100644 index 0000000000..e448c414a3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/KahaQueueTest.java @@ -0,0 +1,37 @@ +/** + * 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.perf; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +/** + * + */ +public class KahaQueueTest extends SimpleQueueTest { + final static String config = "org/apache/activemq/perf/kahadbBroker.xml"; + + protected BrokerService createBroker(String uri) throws Exception { + Resource resource = new ClassPathResource(config); + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(resource); + resource = new ClassPathResource(config); + brokerFactory = new BrokerFactoryBean(resource); + brokerFactory.afterPropertiesSet(); + return brokerFactory.getBroker(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/LevelDBDurableTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/LevelDBDurableTopicTest.java new file mode 100644 index 0000000000..7fd1c12f4c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/LevelDBDurableTopicTest.java @@ -0,0 +1,44 @@ +/** +revision 946600 * 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.perf; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; + +/** + * + */ +public class LevelDBDurableTopicTest extends SimpleDurableTopicTest { + + /* + * protected BrokerService createBroker() throws Exception{ Resource + * resource=new ClassPathResource( + * "org/apache/activemq/perf/kahaBroker.xml"); BrokerFactoryBean factory=new + * BrokerFactoryBean(resource); factory.afterPropertiesSet(); BrokerService + * result=factory.getBroker(); result.start(); return result; } + */ + + @Override + protected void configureBroker(BrokerService answer,String uri) throws Exception { + LevelDBStore store = new LevelDBStore(); + answer.setPersistenceAdapter(store); + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(uri); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/LevelDBStoreQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/LevelDBStoreQueueTest.java new file mode 100644 index 0000000000..169c32ea03 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/LevelDBStoreQueueTest.java @@ -0,0 +1,42 @@ +/** + * 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.perf; + +import java.io.File; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; + +/** + * + */ +public class LevelDBStoreQueueTest extends SimpleQueueTest { + + protected void configureBroker(BrokerService answer,String uri) throws Exception { + + File dataFileDir = new File("target/test-amq-data/perfTest/amq"); + + LevelDBStore adaptor = new LevelDBStore(); + adaptor.setDirectory(dataFileDir); + + answer.setPersistenceAdapter(adaptor); + answer.addConnector(uri); + answer.setDeleteAllMessagesOnStartup(true); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/MemoryAllocationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/MemoryAllocationTest.java new file mode 100644 index 0000000000..a6b4380792 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/MemoryAllocationTest.java @@ -0,0 +1,117 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.TemporaryTopic; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class MemoryAllocationTest extends TestCase { + + protected static final int MESSAGE_COUNT = 2000; + private static final Logger LOG = LoggerFactory.getLogger(MemoryAllocationTest.class); + + protected BrokerService broker; + protected String bindAddress = "vm://localhost"; + protected int topicCount; + + public void testPerformance() throws Exception { + ConnectionFactory factory = createConnectionFactory(); + Connection connection = factory.createConnection(); + for (int i = 0; i < MESSAGE_COUNT; i++) { + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = session.createTemporaryTopic(); + session.createConsumer(dest); + MessageProducer mp = session.createProducer(dest); + Message msg = session.createTextMessage("test" + i); + mp.send(msg); + session.close(); + releaseDestination(dest); + if (i % 500 == 0) { + LOG.info("Iterator " + i); + } + } + connection.close(); + } + + protected Destination getDestination(Session session) throws JMSException { + String topicName = getClass().getName() + "." + topicCount++; + return session.createTopic(topicName); + } + + protected void releaseDestination(Destination dest) throws JMSException { + if (dest instanceof TemporaryTopic) { + TemporaryTopic tt = (TemporaryTopic)dest; + tt.delete(); + } else if (dest instanceof TemporaryQueue) { + TemporaryQueue tq = (TemporaryQueue)dest; + tq.delete(); + } + } + + @Override + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(bindAddress); + return cf; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.setPersistent(false); + answer.addConnector(bindAddress); + answer.setDeleteAllMessagesOnStartup(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/NetworkedSyncTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/NetworkedSyncTest.java new file mode 100644 index 0000000000..4a3b20de1b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/NetworkedSyncTest.java @@ -0,0 +1,317 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import junit.framework.TestCase; +import junit.textui.TestRunner; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.apache.xbean.spring.context.ClassPathXmlApplicationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + + +public class NetworkedSyncTest extends TestCase { + + // constants + public static final int MESSAGE_COUNT = 10000; //100000; + public final static String config = "org/apache/activemq/perf/networkSync.xml"; + public final static String broker1URL = "tcp://localhost:61616"; + public final static String broker2URL = "tcp://localhost:62616"; + private final String networkConnectorURL = "static://(" + broker2URL + ")"; + private static final Logger LOG = LoggerFactory.getLogger(NetworkedSyncTest.class); + BrokerService broker1 = null; + BrokerService broker2 = null; + NetworkConnector connector = null; + + /** + * @param name + */ + public NetworkedSyncTest(String name) { + super(name); + LOG.info("Testcase started."); + } + + public static void main(String args[]) { + TestRunner.run(NetworkedSyncTest.class); + } + + /** + * @throws java.lang.Exception + */ + @Override + protected void setUp() throws Exception { + LOG.info("setUp() called."); + ClassPathXmlApplicationContext context1 = null; + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(new ClassPathResource(config)); + assertNotNull(brokerFactory); + + /* start up first broker instance */ + try { + // resolve broker1 + Thread.currentThread().setContextClassLoader( + NetworkedSyncTest.class.getClassLoader()); + context1 = new ClassPathXmlApplicationContext(config); + broker1 = (BrokerService) context1.getBean("broker1"); + + // start the broker + if (!broker1.isStarted()) { + LOG.info("Broker broker1 not yet started. Kicking it off now."); + broker1.start(); + } else { + LOG.info("Broker broker1 already started. Not kicking it off a second time."); + broker1.waitUntilStopped(); + } + } catch (Exception e) { + LOG.error("Error: " + e.getMessage()); + throw e; + // brokerService.stop(); + } + + /* start up second broker instance */ + try { + Thread.currentThread().setContextClassLoader( + NetworkedSyncTest.class.getClassLoader()); + context1 = new ClassPathXmlApplicationContext(config); + broker2 = (BrokerService) context1.getBean("broker2"); + + // start the broker + if (!broker2.isStarted()) { + LOG.info("Broker broker2 not yet started. Kicking it off now."); + broker2.start(); + } else { + LOG.info("Broker broker2 already started. Not kicking it off a second time."); + broker2.waitUntilStopped(); + } + } catch (Exception e) { + LOG.error("Error: " + e.getMessage()); + throw e; + } + + // setup network connector from broker1 to broker2 + connector = broker1.addNetworkConnector(networkConnectorURL); + connector.setBrokerName(broker1.getBrokerName()); + connector.setDuplex(true); + connector.start(); + LOG.info("Network connector created."); + } + + /** + * @throws java.lang.Exception + */ + @Override + protected void tearDown() throws Exception { + + LOG.info("tearDown() called."); + + if (broker1 != null && broker1.isStarted()) { + LOG.info("Broker1 still running, stopping it now."); + broker1.stop(); + } else { + LOG.info("Broker1 not running, nothing to shutdown."); + } + if (broker2 != null && broker2.isStarted()) { + LOG.info("Broker2 still running, stopping it now."); + broker2.stop(); + } else { + LOG.info("Broker2 not running, nothing to shutdown."); + } + + } + + public void testMessageExchange() throws Exception { + LOG.info("testMessageExchange() called."); + + long start = System.currentTimeMillis(); + + // create producer and consumer threads + Thread producer = new Thread(new Producer()); + Thread consumer = new Thread(new Consumer()); + // start threads + consumer.start(); + Thread.sleep(2000); + producer.start(); + + + // wait for threads to finish + producer.join(); + consumer.join(); + long end = System.currentTimeMillis(); + + System.out.println("Duration: "+(end-start)); + } +} + +/** + * Message producer running as a separate thread, connecting to broker1 + * + * @author tmielke + * + */ +class Producer implements Runnable { + + private static final Logger LOG = LoggerFactory.getLogger(Producer.class); + + /** + * connect to broker and constantly send messages + */ + @Override + public void run() { + + Connection connection = null; + Session session = null; + MessageProducer producer = null; + + try { + ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory( + NetworkedSyncTest.broker1URL); + connection = amq.createConnection(); + + connection.setExceptionListener(new javax.jms.ExceptionListener() { + @Override + public void onException(javax.jms.JMSException e) { + e.printStackTrace(); + } + }); + + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic destination = session.createTopic("TEST.FOO"); + + producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + long counter = 0; + + // Create and send message + for (int i = 0; i < NetworkedSyncTest.MESSAGE_COUNT; i++) { + + String text = "Hello world! From: " + + Thread.currentThread().getName() + " : " + + this.hashCode() + ":" + counter; + TextMessage message = session.createTextMessage(text); + producer.send(message); + counter++; + + if ((counter % 1000) == 0) + LOG.info("sent " + counter + " messages"); + + } + } catch (Exception ex) { + LOG.error(ex.toString()); + return; + } finally { + try { + if (producer != null) + producer.close(); + if (session != null) + session.close(); + if (connection != null) + connection.close(); + } catch (Exception e) { + LOG.error("Problem closing down JMS objects: " + e); + } + } + } +} + +/* + * * Message consumer running as a separate thread, connecting to broker2 + * @author tmielke + * + */ +class Consumer implements Runnable { + + private static final Logger LOG = LoggerFactory.getLogger(Consumer.class);; + + + /** + * connect to broker and receive messages + */ + @Override + public void run() { + Connection connection = null; + Session session = null; + MessageConsumer consumer = null; + + try { + ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory( + NetworkedSyncTest.broker2URL); + connection = amq.createConnection(); + // need to set clientID when using durable subscription. + connection.setClientID("tmielke"); + + connection.setExceptionListener(new javax.jms.ExceptionListener() { + @Override + public void onException(javax.jms.JMSException e) { + e.printStackTrace(); + } + }); + + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTopic("TEST.FOO"); + consumer = session.createDurableSubscriber((Topic) destination,"tmielke"); + + long counter = 0; + // Wait for a message + for (int i = 0; i < NetworkedSyncTest.MESSAGE_COUNT; i++) { + Message message2 = consumer.receive(); + if (message2 instanceof TextMessage) { + TextMessage textMessage = (TextMessage) message2; + textMessage.getText(); + // logger.info("Received: " + text); + } else { + LOG.error("Received message of unsupported type. Expecting TextMessage. "+ message2); + } + counter++; + if ((counter % 1000) == 0) + LOG.info("received " + counter + " messages"); + + + } + } catch (Exception e) { + LOG.error("Error in Consumer: " + e); + return; + } finally { + try { + if (consumer != null) + consumer.close(); + if (session != null) + session.close(); + if (connection != null) + connection.close(); + } catch (Exception ex) { + LOG.error("Error closing down JMS objects: " + ex); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/NumberOfDestinationsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/NumberOfDestinationsTest.java new file mode 100644 index 0000000000..f25c0a5923 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/NumberOfDestinationsTest.java @@ -0,0 +1,127 @@ +/** + * 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.perf; + +/** + * A NumberOfDestinationsTest + * + */ +import java.io.File; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * + */ +public class NumberOfDestinationsTest extends TestCase { + protected static final int MESSAGE_COUNT = 1; + protected static final int NUMBER_OF_DESTINATIONS = 100000; + private static final Logger LOG = LoggerFactory.getLogger(NumberOfDestinationsTest.class); + protected BrokerService broker; + protected String bindAddress = "vm://localhost"; + protected int destinationCount; + + public void testDestinations() throws Exception { + ConnectionFactory factory = createConnectionFactory(); + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer mp = session.createProducer(null); + for (int j = 0; j < NUMBER_OF_DESTINATIONS; j++) { + Destination dest = getDestination(session); + + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message msg = session.createTextMessage("test" + i); + mp.send(dest, msg); + + } + if (j % 500 == 0) { + LOG.info("Iterator " + j); + } + } + + connection.close(); + } + + protected Destination getDestination(Session session) throws JMSException { + String topicName = getClass().getName() + "." + destinationCount++; + return session.createTopic(topicName); + } + + @Override + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(bindAddress); + return cf; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + File dataFileDir = new File("target/test-amq-data/perfTest/kahadb"); + + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setDirectory(dataFileDir); + //answer.setUseJmx(false); + + // The setEnableJournalDiskSyncs(false) setting is a little dangerous right now, as I have not verified + // what happens if the index is updated but a journal update is lost. + // Index is going to be in consistent, but can it be repaired? + //kaha.setEnableJournalDiskSyncs(false); + // Using a bigger journal file size makes he take fewer spikes as it is not switching files as often. + //kaha.setJournalMaxFileLength(1024*100); + + // small batch means more frequent and smaller writes + //kaha.setIndexWriteBatchSize(100); + // do the index write in a separate thread + //kaha.setEnableIndexWriteAsync(true); + + answer.setPersistenceAdapter(kaha); + answer.setAdvisorySupport(false); + answer.setEnableStatistics(false); + answer.addConnector(bindAddress); + answer.setDeleteAllMessagesOnStartup(true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfConsumer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfConsumer.java new file mode 100644 index 0000000000..14292b8d50 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfConsumer.java @@ -0,0 +1,140 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.jms.Topic; +import org.apache.activemq.ActiveMQMessageAudit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class PerfConsumer implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(PerfConsumer.class); + protected Connection connection; + protected MessageConsumer consumer; + protected long sleepDuration; + protected long initialDelay; + protected boolean enableAudit = false; + protected ActiveMQMessageAudit audit = new ActiveMQMessageAudit(16 * 1024,20); + protected boolean firstMessage =true; + protected String lastMsgId; + + protected PerfRate rate = new PerfRate(); + + public PerfConsumer(ConnectionFactory fac, Destination dest, String consumerName) throws JMSException { + connection = fac.createConnection(); + connection.setClientID(consumerName); + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + if (dest instanceof Topic && consumerName != null && consumerName.length() > 0) { + consumer = s.createDurableSubscriber((Topic)dest, consumerName); + } else { + consumer = s.createConsumer(dest); + } + consumer.setMessageListener(this); + } + + public PerfConsumer(ConnectionFactory fac, Destination dest) throws JMSException { + this(fac, dest, null); + } + + public void start() throws JMSException { + connection.start(); + rate.reset(); + } + + public void stop() throws JMSException { + connection.stop(); + } + + public void shutDown() throws JMSException { + connection.close(); + } + + public PerfRate getRate() { + return rate; + } + + public void onMessage(Message msg) { + if (firstMessage) { + firstMessage=false; + if (getInitialDelay() > 0) { + try { + Thread.sleep(getInitialDelay()); + } catch (InterruptedException e) { + } + } + } + rate.increment(); + try { + if (enableAudit && !this.audit.isInOrder(msg.getJMSMessageID())) { + LOG.error("Message out of order!!" + msg.getJMSMessageID() + " LAST = " + lastMsgId); + } + if (enableAudit && this.audit.isDuplicate(msg)){ + LOG.error("Duplicate Message!" + msg); + } + lastMsgId=msg.getJMSMessageID(); + } catch (JMSException e1) { + e1.printStackTrace(); + } + try { + if (sleepDuration != 0) { + Thread.sleep(sleepDuration); + } + } catch (InterruptedException e) { + } + } + + public synchronized long getSleepDuration() { + return sleepDuration; + } + + public synchronized void setSleepDuration(long sleepDuration) { + this.sleepDuration = sleepDuration; + } + + public boolean isEnableAudit() { + return enableAudit; + } + + public void setEnableAudit(boolean doAudit) { + this.enableAudit = doAudit; + } + + /** + * @return the initialDelay + */ + public long getInitialDelay() { + return initialDelay; + } + + /** + * @param initialDelay the initialDelay to set + */ + public void setInitialDelay(long initialDelay) { + this.initialDelay = initialDelay; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfProducer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfProducer.java new file mode 100644 index 0000000000..10dc740a31 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfProducer.java @@ -0,0 +1,129 @@ +/** + * 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.perf; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; + +/** + * + */ +public class PerfProducer implements Runnable { + protected Connection connection; + protected MessageProducer producer; + protected PerfRate rate = new PerfRate(); + private final byte[] payload; + private Session session; + private final CountDownLatch stopped = new CountDownLatch(1); + private boolean running; + private final boolean transacted; + private int sleep = 0; + + public PerfProducer(ConnectionFactory fac, Destination dest, byte[] payload) throws JMSException { + this(fac, dest, payload, false); + } + public PerfProducer(ConnectionFactory fac, Destination dest, byte[] payload, boolean transacted) + throws JMSException { + connection = fac.createConnection(); + this.transacted = transacted; + if (transacted) { + session = connection.createSession(true, Session.SESSION_TRANSACTED); + } else { + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + producer = session.createProducer(dest); + this.payload = payload; + + } + + public void setDeliveryMode(int mode) throws JMSException { + producer.setDeliveryMode(mode); + } + + public void setTimeToLive(int ttl) throws JMSException { + producer.setTimeToLive(ttl); + } + + public void shutDown() throws JMSException { + connection.close(); + } + + public PerfRate getRate() { + return rate; + } + + public synchronized void start() throws JMSException { + if (!running) { + rate.reset(); + running = true; + connection.start(); + Thread t = new Thread(this); + t.setName("Producer"); + t.start(); + } + } + + public void stop() throws JMSException, InterruptedException { + synchronized (this) { + running = false; + } + stopped.await(1, TimeUnit.SECONDS); + connection.stop(); + } + + public synchronized boolean isRunning() { + return running; + } + + public void run() { + try { + while (isRunning()) { + BytesMessage msg; + msg = session.createBytesMessage(); + msg.writeBytes(payload); + producer.send(msg); + if(this.transacted) { + this.session.commit(); + } + rate.increment(); + if (sleep > 0) { + Thread.sleep(sleep); + } + } + } catch (Throwable e) { + e.printStackTrace(); + } finally { + stopped.countDown(); + } + } + + public int getSleep() { + return sleep; + } + + public void setSleep(int sleep) { + this.sleep = sleep; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfRate.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfRate.java new file mode 100644 index 0000000000..8f82617521 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/PerfRate.java @@ -0,0 +1,81 @@ +/** + * 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.perf; + +/** + * + */ +public class PerfRate { + + protected int totalCount; + protected int count; + protected long startTime = System.currentTimeMillis(); + + /** + * @return Returns the count. + */ + public int getCount() { + return totalCount; + } + + public synchronized void increment() { + totalCount++; + count++; + } + + public int getRate() { + long endTime = System.currentTimeMillis(); + long totalTime = endTime - startTime; + int result = (int)((count * 1000) / totalTime); + return result; + } + + /** + * Resets the rate sampling. + */ + public synchronized PerfRate cloneAndReset() { + PerfRate rc = new PerfRate(); + rc.totalCount = totalCount; + rc.count = count; + rc.startTime = startTime; + count = 0; + startTime = System.currentTimeMillis(); + return rc; + } + + /** + * Resets the rate sampling. + */ + public void reset() { + count = 0; + startTime = System.currentTimeMillis(); + } + + /** + * @return Returns the totalCount. + */ + public int getTotalCount() { + return totalCount; + } + + /** + * @param totalCount The totalCount to set. + */ + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/QueueConnectionMemoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/QueueConnectionMemoryTest.java new file mode 100644 index 0000000000..ff19f3e80f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/QueueConnectionMemoryTest.java @@ -0,0 +1,83 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class QueueConnectionMemoryTest extends SimpleQueueTest { + private static final transient Logger LOG = LoggerFactory.getLogger(QueueConnectionMemoryTest.class); + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + + } + + @Override + protected Destination createDestination(Session s, String destinationName) throws JMSException { + return s.createTemporaryQueue(); + } + + @Override + public void testPerformance() throws JMSException { + // just cancel super class test + } + + @Override + protected void configureBroker(BrokerService answer,String uri) throws Exception { + LevelDBStore adaptor = new LevelDBStore(); + answer.setPersistenceAdapter(adaptor); + answer.addConnector(uri); + answer.setDeleteAllMessagesOnStartup(true); + } + + public void testMemory() throws Exception { + if (broker == null) { + broker = createBroker(bindAddress); + } + factory = createConnectionFactory(bindAddress); + Connection con = factory.createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + createDestination(session, destinationName); + con.close(); + for (int i = 0; i < 3; i++) { + Connection connection = factory.createConnection(); + connection.start(); + Session s = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = s.createTemporaryQueue(); + s.createConsumer(dest); + LOG.debug("Created connnection: " + i); + Thread.sleep(1000); + } + + Thread.sleep(Integer.MAX_VALUE); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/RunBroker.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/RunBroker.java new file mode 100644 index 0000000000..0e78235b94 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/RunBroker.java @@ -0,0 +1,66 @@ +/** + * 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.perf; + +import java.io.File; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.IOHelper; + +public class RunBroker { + + public static void main(String arg[]) { + + try { + KahaDBPersistenceAdapter kahaDB = new KahaDBPersistenceAdapter(); + File dataFileDir = new File("target/test-amq-data/perfTest/kahadb"); + IOHelper.deleteChildren(dataFileDir); + kahaDB.setDirectory(dataFileDir); + + // The setEnableJournalDiskSyncs(false) setting is a little + // dangerous right now, as I have not verified + // what happens if the index is updated but a journal update is + // lost. + // Index is going to be in consistent, but can it be repaired? + // kaha.setEnableJournalDiskSyncs(false); + // Using a bigger journal file size makes he take fewer spikes as it + // is not switching files as often. + // kaha.setJournalMaxFileLength(1024*1024*100); + + // small batch means more frequent and smaller writes + kahaDB.setIndexWriteBatchSize(1000); + kahaDB.setIndexCacheSize(10000); + + // do the index write in a separate thread + // kahaDB.setEnableIndexWriteAsync(true); + BrokerService broker = new BrokerService(); + broker.setUseJmx(false); + // broker.setPersistenceAdapter(adaptor); + broker.setPersistenceAdapter(kahaDB); + // broker.setPersistent(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector("tcp://0.0.0.0:61616"); + broker.start(); + System.err.println("Running"); + Thread.sleep(Long.MAX_VALUE); + } catch (Throwable e) { + e.printStackTrace(); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleDurableTopicNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleDurableTopicNetworkTest.java new file mode 100644 index 0000000000..c4fd892253 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleDurableTopicNetworkTest.java @@ -0,0 +1,45 @@ +/** + * 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.perf; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; + + +public class SimpleDurableTopicNetworkTest extends SimpleNetworkTest { + + protected void setUp() throws Exception { + numberofProducers=1; + numberOfConsumers=1; + sampleCount=1000; + playloadSize = 1024; + super.setUp(); + } + + + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte payload[]) throws JMSException { + PerfProducer pp = new PerfProducer(fac, dest, payload); + pp.setDeliveryMode(DeliveryMode.PERSISTENT); + return pp; + } + + protected PerfConsumer createConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + return new PerfConsumer(fac, dest, "subs:" + number); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleDurableTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleDurableTopicTest.java new file mode 100644 index 0000000000..9ca25c1a13 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleDurableTopicTest.java @@ -0,0 +1,74 @@ +/** + * 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.perf; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStoreFactory; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; + +/** + * + */ +public class SimpleDurableTopicTest extends SimpleTopicTest { + protected long initialConsumerDelay = 0; + @Override + protected void setUp() throws Exception { + numberOfDestinations=1; + numberOfConsumers = 1; + numberofProducers = Integer.parseInt(System.getProperty("SimpleDurableTopicTest.numberofProducers", "20"), 20); + sampleCount= Integer.parseInt(System.getProperty("SimpleDurableTopicTest.sampleCount", "1000"), 10); + playloadSize = 1024; + super.setUp(); + } + + + @Override + protected void configureBroker(BrokerService answer,String uri) throws Exception { + LevelDBStoreFactory persistenceFactory = new LevelDBStoreFactory(); + answer.setPersistenceFactory(persistenceFactory); + //answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(uri); + answer.setUseShutdownHook(false); + } + + @Override + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte payload[]) throws JMSException { + PerfProducer pp = new PerfProducer(fac, dest, payload); + pp.setDeliveryMode(DeliveryMode.PERSISTENT); + return pp; + } + + @Override + protected PerfConsumer createConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + PerfConsumer result = new PerfConsumer(fac, dest, "subs:" + number); + result.setInitialDelay(this.initialConsumerDelay); + return result; + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory(String uri) throws Exception { + ActiveMQConnectionFactory result = super.createConnectionFactory(uri); + //result.setSendAcksAsync(false); + return result; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNetworkTest.java new file mode 100644 index 0000000000..fdb14e2371 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNetworkTest.java @@ -0,0 +1,144 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.network.NetworkConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class SimpleNetworkTest extends SimpleTopicTest { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleNetworkTest.class); + protected String consumerBindAddress = "tcp://localhost:61616"; + protected String producerBindAddress = "tcp://localhost:61617"; + protected static final String CONSUMER_BROKER_NAME = "Consumer"; + protected static final String PRODUCER_BROKER_NAME = "Producer"; + protected BrokerService consumerBroker; + protected BrokerService producerBroker; + protected ActiveMQConnectionFactory consumerFactory; + protected ActiveMQConnectionFactory producerFactory; + + + protected void setUp() throws Exception { + if (consumerBroker == null) { + consumerBroker = createConsumerBroker(consumerBindAddress); + } + if (producerBroker == null) { + producerBroker = createProducerBroker(producerBindAddress); + } + consumerFactory = createConnectionFactory(consumerBindAddress); + consumerFactory.setDispatchAsync(true); + ActiveMQPrefetchPolicy policy = new ActiveMQPrefetchPolicy(); + policy.setQueuePrefetch(100); + consumerFactory.setPrefetchPolicy(policy); + producerFactory = createConnectionFactory(producerBindAddress); + Connection con = consumerFactory.createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + producers = new PerfProducer[numberofProducers*numberOfDestinations]; + consumers = new PerfConsumer[numberOfConsumers*numberOfDestinations]; + + for (int k =0; k < numberOfDestinations;k++) { + Destination destination = createDestination(session, destinationName+":"+k); + LOG.info("Testing against destination: " + destination); + for (int i = 0; i < numberOfConsumers; i++) { + consumers[i] = createConsumer(consumerFactory, destination, i); + consumers[i].start(); + } + for (int i = 0; i < numberofProducers; i++) { + array = new byte[playloadSize]; + for (int j = i; j < array.length; j++) { + array[j] = (byte)j; + } + producers[i] = createProducer(producerFactory, destination, i, array); + producers[i].start(); + + } + } + con.close(); + } + + protected void tearDown() throws Exception { + for (int i = 0; i < numberOfConsumers; i++) { + consumers[i].shutDown(); + } + for (int i = 0; i < numberofProducers; i++) { + producers[i].shutDown(); + } + + if (producerBroker != null) { + producerBroker.stop(); + producerBroker = null; + } + if (consumerBroker != null) { + consumerBroker.stop(); + consumerBroker = null; + } + } + + protected BrokerService createConsumerBroker(String uri) throws Exception { + BrokerService answer = new BrokerService(); + configureConsumerBroker(answer,uri); + answer.start(); + return answer; + } + + protected void configureConsumerBroker(BrokerService answer,String uri) throws Exception { + configureBroker(answer); + answer.setPersistent(false); + answer.setBrokerName(CONSUMER_BROKER_NAME); + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(uri); + answer.setUseShutdownHook(false); + } + + protected BrokerService createProducerBroker(String uri) throws Exception { + BrokerService answer = new BrokerService(); + configureProducerBroker(answer,uri); + answer.start(); + return answer; + } + + protected void configureProducerBroker(BrokerService answer,String uri) throws Exception { + configureBroker(answer); + answer.setBrokerName(PRODUCER_BROKER_NAME); + answer.setMonitorConnectionSplits(false); + //answer.setSplitSystemUsageForProducersConsumers(true); + answer.setPersistent(false); + answer.setDeleteAllMessagesOnStartup(true); + NetworkConnector connector = answer.addNetworkConnector("static://"+consumerBindAddress); + //connector.setNetworkTTL(3); + //connector.setDynamicOnly(true); + connector.setDuplex(true); + answer.addConnector(uri); + answer.setUseShutdownHook(false); + } + + protected void configureBroker(BrokerService service) throws Exception{ + + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentQueueNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentQueueNetworkTest.java new file mode 100644 index 0000000000..7011a35020 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentQueueNetworkTest.java @@ -0,0 +1,83 @@ +/** + * 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.perf; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Session; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; + +public class SimpleNonPersistentQueueNetworkTest extends SimpleNetworkTest { + + protected void setUp()throws Exception { + numberOfDestinations =20; + super.setUp(); + } + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte[] payload) throws JMSException { + PerfProducer pp = new PerfProducer(fac, dest, payload); + pp.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + // pp.setTimeToLive(1000); + //pp.setSleep(1); + return pp; + } + + protected PerfConsumer createConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + PerfConsumer consumer = new PerfConsumer(fac, dest); + boolean enableAudit = numberOfConsumers <= 1; + System.out.println("Enable Audit = " + enableAudit); + consumer.setEnableAudit(false); + return consumer; + } + + public void testPerformance() throws JMSException, InterruptedException { + //Thread.sleep(5000); + super.testPerformance(); + } + + protected Destination createDestination(Session s, String destinationName) throws JMSException { + return s.createQueue(destinationName); + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.setPersistent(false); + answer.setMonitorConnectionSplits(true); + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setQueue(">"); + entry.setMemoryLimit(1024 * 1024 * 100); // Set to 1 MB + entry.setOptimizedDispatch(true); + entry.setProducerFlowControl(true); + entry.setMaxPageSize(10); + entry.setLazyDispatch(false); + policyEntries.add(entry); + + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + answer.setDestinationPolicy(policyMap); + super.configureBroker(answer); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentQueueTest.java new file mode 100644 index 0000000000..1a531f4619 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentQueueTest.java @@ -0,0 +1,78 @@ +/** + * 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.perf; + +import java.util.ArrayList; +import java.util.List; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; + +/** + * + */ +public class SimpleNonPersistentQueueTest extends SimpleQueueTest { + + @Override + protected void setUp() throws Exception { + numberOfConsumers = 1; + numberofProducers = 1; + super.setUp(); + } + @Override + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte[] payload) throws JMSException { + PerfProducer pp = new PerfProducer(fac, dest, payload); + pp.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + //pp.setTimeToLive(100); + return pp; + } + + @Override + protected PerfConsumer createConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + PerfConsumer result = new PerfConsumer(fac, dest); + result.setInitialDelay(10*1000); + boolean enableAudit = numberOfConsumers <= 1; + System.err.println("Enable Audit = " + enableAudit); + result.setEnableAudit(enableAudit); + + return result; + } + + + @Override + protected void configureBroker(BrokerService answer,String uri) throws Exception { + // answer.setPersistent(false); + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setQueue(">"); + entry.setMemoryLimit(1024 * 1024 * 1); // Set to 1 MB + entry.setOptimizedDispatch(true); + entry.setLazyDispatch(true); + policyEntries.add(entry); + + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + answer.setDestinationPolicy(policyMap); + super.configureBroker(answer, uri); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentTopicTest.java new file mode 100644 index 0000000000..eacc6e1775 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleNonPersistentTopicTest.java @@ -0,0 +1,34 @@ +/** + * 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.perf; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; + +/** + * + */ +public class SimpleNonPersistentTopicTest extends SimpleTopicTest { + + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte[] payload) throws JMSException { + PerfProducer pp = new PerfProducer(fac, dest, payload); + pp.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + return pp; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleQueueTest.java new file mode 100644 index 0000000000..30708f4c79 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleQueueTest.java @@ -0,0 +1,53 @@ +/** + * 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.perf; + +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Session; + +/** + * + */ +public class SimpleQueueTest extends SimpleTopicTest { + + protected long initialConsumerDelay = 0; + protected long consumerSleep = 0; + @Override + protected Destination createDestination(Session s, String destinationName) throws JMSException { + return s.createQueue(destinationName); + } + + @Override + protected void setUp() throws Exception { + numberOfConsumers = 1; + super.setUp(); + } + + @Override + protected PerfConsumer createConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + PerfConsumer consumer = new PerfConsumer(fac, dest); + consumer.setInitialDelay(this.initialConsumerDelay); + consumer.setSleepDuration(this.consumerSleep); + boolean enableAudit = numberOfConsumers <= 1; + System.err.println("Enable Audit = " + enableAudit); + consumer.setEnableAudit(enableAudit); + return consumer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleTopicTest.java new file mode 100644 index 0000000000..e0494ab96d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SimpleTopicTest.java @@ -0,0 +1,206 @@ +/** + * 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.perf; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class SimpleTopicTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleTopicTest.class); + + protected BrokerService broker; + protected String clientURI = "tcp://localhost:61616?wireFormat.cacheEnabled=true&wireFormat.tightEncodingEnabled=true&jms.useAsyncSend=false&wireFormat.maxInactivityDuration=0"; + // protected String clientURI="tcp://localhost:61616"; + protected String bindAddress = "tcp://localhost:61616?wireFormat.maxInactivityDuration=0"; + // protected String bindAddress = "tcp://localhost:61616"; + // protected String bindAddress="vm://localhost?marshal=true"; + // protected String bindAddress="vm://localhost"; + protected PerfProducer[] producers; + protected PerfConsumer[] consumers; + protected String destinationName = getClass().getName(); + protected int sampleCount = 20; + protected long sampleInternal = 10000; + protected int numberOfDestinations = 1; + protected int numberOfConsumers = 1; + protected int numberofProducers = 1; + protected int totalNumberOfProducers; + protected int totalNumberOfConsumers; + protected int playloadSize = 12; + protected byte[] array; + protected ConnectionFactory factory; + + /** + * Sets up a test where the producer and consumer have their own connection. + * + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(bindAddress); + } + factory = createConnectionFactory(clientURI); + Connection con = factory.createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + LOG.info("Running " + numberofProducers + " producer(s) and " + numberOfConsumers + " consumer(s) per " + numberOfDestinations + " Destination(s)"); + + totalNumberOfConsumers = numberOfConsumers * numberOfDestinations; + totalNumberOfProducers = numberofProducers * numberOfDestinations; + producers = new PerfProducer[totalNumberOfProducers]; + consumers = new PerfConsumer[totalNumberOfConsumers]; + int consumerCount = 0; + int producerCount = 0; + for (int k = 0; k < numberOfDestinations; k++) { + Destination destination = createDestination(session, destinationName + ":" + k); + LOG.info("Testing against destination: " + destination); + for (int i = 0; i < numberOfConsumers; i++) { + consumers[consumerCount] = createConsumer(factory, destination, consumerCount); + consumerCount++; + } + for (int i = 0; i < numberofProducers; i++) { + array = new byte[playloadSize]; + for (int j = i; j < array.length; j++) { + array[j] = (byte) j; + } + producers[producerCount] = createProducer(factory, destination, i, array); + producerCount++; + } + } + con.close(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + for (int i = 0; i < numberOfConsumers; i++) { + consumers[i].shutDown(); + } + for (int i = 0; i < numberofProducers; i++) { + producers[i].shutDown(); + } + if (broker != null) { + broker.stop(); + broker = null; + } + } + + protected Destination createDestination(Session s, String destinationName) throws JMSException { + return s.createTopic(destinationName); + } + + /** + * Factory method to create a new broker + * + * @throws Exception + */ + protected BrokerService createBroker(String uri) throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer, uri); + answer.start(); + return answer; + } + + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte[] payload) throws JMSException { + return new PerfProducer(fac, dest, payload); + } + + protected PerfConsumer createConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + return new PerfConsumer(fac, dest); + } + + protected void configureBroker(BrokerService answer, String uri) throws Exception { + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector(uri); + answer.setUseShutdownHook(false); + } + + protected ActiveMQConnectionFactory createConnectionFactory(String uri) throws Exception { + return new ActiveMQConnectionFactory(uri); + } + + public void testPerformance() throws JMSException, InterruptedException { + for (int i = 0; i < totalNumberOfConsumers; i++) { + consumers[i].start(); + } + for (int i = 0; i < totalNumberOfProducers; i++) { + producers[i].start(); + } + LOG.info("Sampling performance " + sampleCount + " times at a " + sampleInternal + " ms interval."); + for (int i = 0; i < sampleCount; i++) { + Thread.sleep(sampleInternal); + dumpProducerRate(); + dumpConsumerRate(); + } + for (int i = 0; i < totalNumberOfProducers; i++) { + producers[i].stop(); + } + for (int i = 0; i < totalNumberOfConsumers; i++) { + consumers[i].stop(); + } + } + + @SuppressWarnings("unused") + protected void dumpProducerRate() { + int totalRate = 0; + int totalCount = 0; + String producerString = "Producers:"; + for (int i = 0; i < producers.length; i++) { + PerfRate rate = producers[i].getRate().cloneAndReset(); + totalRate += rate.getRate(); + totalCount += rate.getTotalCount(); + producerString += "[" + i + ":" + rate.getRate() + "," + rate.getTotalCount() + "];"; + } + if (producers != null && producers.length > 0) { + int avgRate = totalRate / producers.length; + System.out.println("Avg producer rate = " + avgRate + " msg/sec | Total rate = " + totalRate + ", sent = " + totalCount); + // System.out.println(producerString); + } + } + + protected void dumpConsumerRate() { + int totalRate = 0; + int totalCount = 0; + String consumerString = "Consumers:"; + for (int i = 0; i < consumers.length; i++) { + PerfRate rate = consumers[i].getRate().cloneAndReset(); + totalRate += rate.getRate(); + totalCount += rate.getTotalCount(); + consumerString += "[" + i + ":" + rate.getRate() + "," + rate.getTotalCount() + "];"; + } + if (consumers != null && consumers.length > 0) { + int avgRate = totalRate / consumers.length; + System.out.println("Avg consumer rate = " + avgRate + " msg/sec | Total rate = " + totalRate + ", received = " + totalCount); + System.out.println(consumerString); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowConsumer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowConsumer.java new file mode 100644 index 0000000000..913e86a096 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowConsumer.java @@ -0,0 +1,50 @@ +/** + * 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.perf; + +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class SlowConsumer extends PerfConsumer { + private static final transient Logger LOG = LoggerFactory.getLogger(SlowConsumer.class); + + public SlowConsumer(ConnectionFactory fac, Destination dest, String consumerName) throws JMSException { + super(fac, dest, consumerName); + } + + public SlowConsumer(ConnectionFactory fac, Destination dest) throws JMSException { + super(fac, dest, null); + } + + public void onMessage(Message msg) { + super.onMessage(msg); + LOG.debug("GOT A MSG " + msg); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowConsumerTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowConsumerTopicTest.java new file mode 100644 index 0000000000..8c87aa8842 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowConsumerTopicTest.java @@ -0,0 +1,74 @@ +/** + * 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.perf; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * + */ +public class SlowConsumerTopicTest extends SimpleTopicTest { + + protected PerfConsumer[] slowConsumers; + + protected void setUp() throws Exception { + + playloadSize = 10 * 1024; + super.setUp(); + } + + + protected PerfConsumer createConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + PerfConsumer result = new SlowConsumer(fac, dest); + return result; + } + + protected PerfProducer createProducer(ConnectionFactory fac, Destination dest, int number, byte[] payload) throws JMSException { + PerfProducer result = super.createProducer(fac, dest, number, payload); + result.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + result.setSleep(10); + return result; + } + + protected BrokerService createBroker(String url) throws Exception { + Resource resource = new ClassPathResource("org/apache/activemq/perf/slowConsumerBroker.xml"); + System.err.println("CREATE BROKER FROM " + resource); + BrokerFactoryBean factory = new BrokerFactoryBean(resource); + factory.afterPropertiesSet(); + BrokerService broker = factory.getBroker(); + + broker.start(); + return broker; + } + + protected ActiveMQConnectionFactory createConnectionFactory(String uri) throws Exception { + ActiveMQConnectionFactory result = super.createConnectionFactory(uri); + ActiveMQPrefetchPolicy policy = new ActiveMQPrefetchPolicy(); + policy.setTopicPrefetch(10); + result.setPrefetchPolicy(policy); + return result; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowDurableConsumerTopicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowDurableConsumerTopicTest.java new file mode 100644 index 0000000000..c71cc5ab2e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/SlowDurableConsumerTopicTest.java @@ -0,0 +1,35 @@ +/** + * 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.perf; + +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; + +/** + * + */ +public class SlowDurableConsumerTopicTest extends SlowConsumerTopicTest { + + protected PerfConsumer[] slowConsumers; + protected int numberOfSlowConsumers = 1; + + protected PerfConsumer createSlowConsumer(ConnectionFactory fac, Destination dest, int number) throws JMSException { + return new SlowConsumer(fac, dest, "durableSlowConsumer" + number); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/TemporaryTopicMemoryAllocationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/TemporaryTopicMemoryAllocationTest.java new file mode 100644 index 0000000000..c379b9c6ad --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/TemporaryTopicMemoryAllocationTest.java @@ -0,0 +1,34 @@ +/** + * 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.perf; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Session; + +/** + * + */ +public class TemporaryTopicMemoryAllocationTest extends MemoryAllocationTest { + public TemporaryTopicMemoryAllocationTest() { + super(); + } + + protected Destination getDestination(Session session) throws JMSException { + return session.createTemporaryTopic(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/kahaBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/kahaBroker.xml new file mode 100644 index 0000000000..1262436d20 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/kahaBroker.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/kahadbBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/kahadbBroker.xml new file mode 100644 index 0000000000..226a441eaf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/kahadbBroker.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/networkSync.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/networkSync.xml new file mode 100644 index 0000000000..7fb9dceb5b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/networkSync.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/slowConsumerBroker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/slowConsumerBroker.xml new file mode 100644 index 0000000000..ac0e8bcec3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/perf/slowConsumerBroker.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/plugin/BrokerStatisticsPluginTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/plugin/BrokerStatisticsPluginTest.java new file mode 100644 index 0000000000..b2e4bddfe5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/plugin/BrokerStatisticsPluginTest.java @@ -0,0 +1,214 @@ +/** + * 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.plugin; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A BrokerStatisticsPluginTest + * A testcase for https://issues.apache.org/activemq/browse/AMQ-2379 + * + */ +public class BrokerStatisticsPluginTest extends TestCase{ + private static final Logger LOG = LoggerFactory.getLogger(BrokerStatisticsPluginTest.class); + + private Connection connection; + private BrokerService broker; + + public void testBrokerStats() throws Exception{ + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue replyTo = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(replyTo); + Queue query = session.createQueue(StatisticsBroker.STATS_BROKER_PREFIX); + MessageProducer producer = session.createProducer(query); + Message msg = session.createMessage(); + msg.setJMSReplyTo(replyTo); + producer.send(msg); + MapMessage reply = (MapMessage) consumer.receive(10*1000); + assertNotNull(reply); + assertTrue(reply.getMapNames().hasMoreElements()); + assertTrue(reply.getJMSTimestamp() > 0); + assertEquals(Message.DEFAULT_PRIORITY, reply.getJMSPriority()); + /* + for (Enumeration e = reply.getMapNames();e.hasMoreElements();) { + String name = e.nextElement().toString(); + System.err.println(name+"="+reply.getObject(name)); + } + */ + } + + public void testBrokerStatsReset() throws Exception{ + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue replyTo = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(replyTo); + Queue testQueue = session.createQueue("Test.Queue"); + Queue query = session.createQueue(StatisticsBroker.STATS_BROKER_PREFIX); + MessageProducer producer = session.createProducer(null); + + producer.send(testQueue, session.createMessage()); + + Message msg = session.createMessage(); + msg.setJMSReplyTo(replyTo); + producer.send(query, msg); + MapMessage reply = (MapMessage) consumer.receive(10*1000); + assertNotNull(reply); + assertTrue(reply.getMapNames().hasMoreElements()); + assertTrue(reply.getLong("enqueueCount") >= 1); + + msg = session.createMessage(); + msg.setBooleanProperty(StatisticsBroker.STATS_BROKER_RESET_HEADER, true); + msg.setJMSReplyTo(replyTo); + producer.send(query, msg); + reply = (MapMessage) consumer.receive(10*1000); + assertNotNull(reply); + assertTrue(reply.getMapNames().hasMoreElements()); + assertEquals(0, reply.getLong("enqueueCount")); + assertTrue(reply.getJMSTimestamp() > 0); + assertEquals(Message.DEFAULT_PRIORITY, reply.getJMSPriority()); + } + + public void testDestinationStats() throws Exception{ + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue replyTo = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(replyTo); + Queue testQueue = session.createQueue("Test.Queue"); + MessageProducer producer = session.createProducer(null); + Queue query = session.createQueue(StatisticsBroker.STATS_DESTINATION_PREFIX + testQueue.getQueueName()); + Message msg = session.createMessage(); + + producer.send(testQueue,msg); + + msg.setJMSReplyTo(replyTo); + producer.send(query,msg); + MapMessage reply = (MapMessage) consumer.receive(10 * 1000); + assertNotNull(reply); + assertTrue(reply.getMapNames().hasMoreElements()); + assertTrue(reply.getJMSTimestamp() > 0); + assertEquals(Message.DEFAULT_PRIORITY, reply.getJMSPriority()); + /* + for (Enumeration e = reply.getMapNames();e.hasMoreElements();) { + String name = e.nextElement().toString(); + System.err.println(name+"="+reply.getObject(name)); + } + */ + } + + public void testDestinationStatsWithDot() throws Exception{ + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue replyTo = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(replyTo); + Queue testQueue = session.createQueue("Test.Queue"); + MessageProducer producer = session.createProducer(null); + Queue query = session.createQueue(StatisticsBroker.STATS_DESTINATION_PREFIX + "." + testQueue.getQueueName()); + Message msg = session.createMessage(); + + producer.send(testQueue,msg); + + msg.setJMSReplyTo(replyTo); + producer.send(query,msg); + MapMessage reply = (MapMessage) consumer.receive(10 * 1000); + assertNotNull(reply); + assertTrue(reply.getMapNames().hasMoreElements()); + assertTrue(reply.getJMSTimestamp() > 0); + assertEquals(Message.DEFAULT_PRIORITY, reply.getJMSPriority()); + /* + for (Enumeration e = reply.getMapNames();e.hasMoreElements();) { + String name = e.nextElement().toString(); + System.err.println(name+"="+reply.getObject(name)); + } + */ + } + + @SuppressWarnings("unused") + public void testSubscriptionStats() throws Exception{ + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue replyTo = session.createTemporaryQueue(); + MessageConsumer consumer = session.createConsumer(replyTo); + Queue testQueue = session.createQueue("Test.Queue"); + MessageConsumer testConsumer = session.createConsumer(testQueue); + MessageProducer producer = session.createProducer(null); + Queue query = session.createQueue(StatisticsBroker.STATS_SUBSCRIPTION_PREFIX); + Message msg = session.createMessage(); + + producer.send(testQueue,msg); + + msg.setJMSReplyTo(replyTo); + producer.send(query,msg); + MapMessage reply = (MapMessage) consumer.receive(10 * 1000); + assertNotNull(reply); + assertTrue(reply.getMapNames().hasMoreElements()); + assertTrue(reply.getJMSTimestamp() > 0); + assertEquals(Message.DEFAULT_PRIORITY, reply.getJMSPriority()); + + /*for (Enumeration e = reply.getMapNames();e.hasMoreElements();) { + String name = e.nextElement().toString(); + System.err.println(name+"="+reply.getObject(name)); + }*/ + } + + @Override + protected void setUp() throws Exception { + broker = createBroker(); + ConnectionFactory factory = new ActiveMQConnectionFactory(broker.getTransportConnectorURIsAsMap().get("tcp")); + connection = factory.createConnection(); + connection.start(); + } + + @Override + protected void tearDown() throws Exception{ + if (this.connection != null) { + this.connection.close(); + } + if (this.broker!=null) { + this.broker.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + BrokerPlugin[] plugins = new BrokerPlugin[1]; + plugins[0] = new StatisticsBrokerPlugin(); + answer.setPlugins(plugins); + answer.setDeleteAllMessagesOnStartup(true); + answer.addConnector("tcp://localhost:0"); + answer.start(); + return answer; + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/plugin/statistics-plugin-broker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/plugin/statistics-plugin-broker.xml new file mode 100644 index 0000000000..ad3933a0c1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/plugin/statistics-plugin-broker.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/pool/JmsSendReceiveTwoConnectionsWithSenderUsingPoolTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/pool/JmsSendReceiveTwoConnectionsWithSenderUsingPoolTest.java new file mode 100644 index 0000000000..05ba17790a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/pool/JmsSendReceiveTwoConnectionsWithSenderUsingPoolTest.java @@ -0,0 +1,47 @@ +/** + * 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.pool; + +import javax.jms.Connection; + +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsSendReceiveTwoConnectionsWithSenderUsingPoolTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + protected static final Logger LOG = LoggerFactory.getLogger(JmsSendReceiveTwoConnectionsWithSenderUsingPoolTest.class); + protected PooledConnectionFactory senderConnectionFactory = new PooledConnectionFactory("vm://localhost?broker.persistent=false"); + + protected Connection createSendConnection() throws Exception { + return senderConnectionFactory.createConnection(); + } + + protected void setUp() throws Exception { + verbose = true; + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + senderConnectionFactory.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/AMQ4889Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/AMQ4889Test.java new file mode 100644 index 0000000000..8ee85e099e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/AMQ4889Test.java @@ -0,0 +1,135 @@ +/** + * 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.proxy; + + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.security.AuthenticationUser; +import org.apache.activemq.security.SimpleAuthenticationPlugin; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSSecurityException; +import javax.jms.Session; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class AMQ4889Test { + protected static final Logger LOG = LoggerFactory.getLogger(AMQ4889Test.class); + + public static final String USER = "user"; + public static final String GOOD_USER_PASSWORD = "password"; + public static final String WRONG_PASSWORD = "wrongPassword"; + public static final String PROXY_URI = "tcp://localhost:6002"; + public static final String LOCAL_URI = "tcp://localhost:6001"; + + protected BrokerService brokerService; + private ProxyConnector proxyConnector; + protected TransportConnector transportConnector; + protected ConnectionFactory connectionFactory; + + private static final Integer ITERATIONS = 100; + + protected BrokerService createBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setPersistent(false); + + ArrayList plugins = new ArrayList(); + BrokerPlugin authenticationPlugin = configureAuthentication(); + plugins.add(authenticationPlugin); + BrokerPlugin[] array = new BrokerPlugin[plugins.size()]; + brokerService.setPlugins(plugins.toArray(array)); + + transportConnector = brokerService.addConnector(LOCAL_URI); + proxyConnector = new ProxyConnector(); + proxyConnector.setName("proxy"); + proxyConnector.setBind(new URI(PROXY_URI)); + proxyConnector.setRemote(new URI(LOCAL_URI)); + brokerService.addProxyConnector(proxyConnector); + + brokerService.start(); + brokerService.waitUntilStarted(); + + return brokerService; + } + + protected BrokerPlugin configureAuthentication() throws Exception { + List users = new ArrayList(); + users.add(new AuthenticationUser(USER, GOOD_USER_PASSWORD, "users")); + SimpleAuthenticationPlugin authenticationPlugin = new SimpleAuthenticationPlugin(users); + + return authenticationPlugin; + } + + @Before + public void setUp() throws Exception { + brokerService = createBroker(); + connectionFactory = new ActiveMQConnectionFactory(PROXY_URI); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + + @Test(timeout = 1 * 60 * 1000) + public void testForConnectionLeak() throws Exception { + Integer expectedConnectionCount = 0; + for (int i=0; i < ITERATIONS; i++) { + try { + if (i % 2 == 0) { + LOG.debug("Iteration {} adding bad connection", i); + Connection connection = connectionFactory.createConnection(USER, WRONG_PASSWORD); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + fail("createSession should fail"); + } else { + LOG.debug("Iteration {} adding good connection", i); + Connection connection = connectionFactory.createConnection(USER, GOOD_USER_PASSWORD); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + expectedConnectionCount++; + } + // + } catch (JMSSecurityException e) { + } + LOG.debug("Iteration {} Connections? {}", i, proxyConnector.getConnectionCount()); + } + final Integer val = expectedConnectionCount; + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return val.equals(proxyConnector.getConnectionCount()); + } + }, 20); + assertEquals(val, proxyConnector.getConnectionCount()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyConnectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyConnectorTest.java new file mode 100644 index 0000000000..bf14a05bf2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyConnectorTest.java @@ -0,0 +1,103 @@ +/** + * 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.proxy; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; + +public class ProxyConnectorTest extends ProxyTestSupport { + + public ActiveMQDestination destination; + public byte destinationType; + public int deliveryMode; + + public static Test suite() { + return suite(ProxyConnectorTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + } + + public void initCombosForTestSendAndConsume() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destinationType", new Object[] {Byte.valueOf(ActiveMQDestination.TOPIC_TYPE)}); + } + + public void testSendAndConsume() throws Exception { + + // Start a producer on local broker using the proxy + StubConnection connection1 = createProxyConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + ProducerInfo producerInfo = createProducerInfo(sessionInfo1); + connection1.send(connectionInfo1); + connection1.send(sessionInfo1); + connection1.send(producerInfo); + + destination = createDestinationInfo(connection1, connectionInfo1, destinationType); + ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + connection1.send(consumerInfo1); + + // Start a consumer on a remote broker using a proxy connection. + StubConnection connection2 = createRemoteProxyConnection(); + ConnectionInfo connectionInfo2 = createConnectionInfo(); + SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + + ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + connection2.send(consumerInfo2); + + // Give broker enough time to receive and register the consumer info + // Either that or make consumer retroactive + try { + Thread.sleep(2000); + } catch (Exception e) { + e.printStackTrace(); + } + + // Send the message to the local broker. + connection1.request(createMessage(producerInfo, destination, deliveryMode)); + + // Verify that the message Was sent to the remote broker and the local + // broker. + Message m; + m = receiveMessage(connection1); + assertNotNull(m); + assertNoMessagesLeft(connection1); + + m = receiveMessage(connection2); + assertNotNull(m); + assertNoMessagesLeft(connection2); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyFailoverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyFailoverTest.java new file mode 100644 index 0000000000..db0a664b60 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyFailoverTest.java @@ -0,0 +1,97 @@ +/** + * 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.proxy; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.ConsumerThread; +import org.apache.activemq.util.ProducerThread; + +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Session; +import java.net.URI; + +public class ProxyFailoverTest extends TestCase { + + BrokerService proxyBroker; + BrokerService remoteBroker; + + @Override + protected void setUp() throws Exception { + startRemoteBroker(true); + proxyBroker = new BrokerService(); + ProxyConnector connector = new ProxyConnector(); + connector.setBind(new URI("tcp://localhost:51618")); + connector.setProxyToLocalBroker(false); + connector.setRemote(new URI("failover:(tcp://localhost:61616)")); + proxyBroker.addProxyConnector(connector); + proxyBroker.setPersistent(false); + proxyBroker.setUseJmx(false); + proxyBroker.start(); + proxyBroker.waitUntilStarted(); + } + + @Override + protected void tearDown() throws Exception { + proxyBroker.stop(); + proxyBroker.waitUntilStopped(); + remoteBroker.stop(); + remoteBroker.waitUntilStopped(); + } + + public void testFailover() throws Exception { + ActiveMQConnectionFactory producerFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616,tcp://localhost:61626)?randomize=false"); + Connection producerConnection = producerFactory.createConnection(); + producerConnection.start(); + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ProducerThread producer = new ProducerThread(producerSession, producerSession.createQueue("ProxyTest")); + producer.setSleep(10); + producer.start(); + + ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory("tcp://localhost:51618"); + Connection consumerConnection = consumerFactory.createConnection(); + consumerConnection.start(); + Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ConsumerThread consumer = new ConsumerThread(consumerSession, consumerSession.createQueue("ProxyTest")); + consumer.start(); + + TimeUnit.SECONDS.sleep(15); + + remoteBroker.stop(); + remoteBroker.waitUntilStopped(); + startRemoteBroker(false); + + producer.join(); + consumer.join(); + + assertEquals(1000, consumer.getReceived()); + } + + protected void startRemoteBroker(boolean delete) throws Exception { + remoteBroker = new BrokerService(); + remoteBroker.addConnector("tcp://localhost:61616"); + if (delete) { + remoteBroker.deleteAllMessages(); + } + remoteBroker.setUseJmx(false); + remoteBroker.start(); + remoteBroker.waitUntilStarted(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyTestSupport.java new file mode 100644 index 0000000000..2c884ec7ca --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/proxy/ProxyTestSupport.java @@ -0,0 +1,137 @@ +/** + * 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.proxy; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTestSupport; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.usage.SystemUsage; + +public class ProxyTestSupport extends BrokerTestSupport { + + protected ArrayList connections = new ArrayList(); + + protected TransportConnector connector; + + protected PersistenceAdapter remotePersistenceAdapter; + protected BrokerService remoteBroker; + protected SystemUsage remoteMemoryManager; + protected TransportConnector remoteConnector; + private ProxyConnector proxyConnector; + private ProxyConnector remoteProxyConnector; + + protected BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setBrokerName("broker1"); + service.setPersistent(false); + service.setUseJmx(false); + + connector = service.addConnector(getLocalURI()); + proxyConnector = new ProxyConnector(); + proxyConnector.setName("proxy"); + proxyConnector.setBind(new URI(getLocalProxyURI())); + proxyConnector.setRemote(new URI("fanout:static://" + getRemoteURI())); + service.addProxyConnector(proxyConnector); + + return service; + } + + protected BrokerService createRemoteBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setBrokerName("broker2"); + service.setPersistent(false); + service.setUseJmx(false); + + remoteConnector = service.addConnector(getRemoteURI()); + remoteProxyConnector = new ProxyConnector(); + remoteProxyConnector.setName("remoteProxy"); + remoteProxyConnector.setBind(new URI(getRemoteProxyURI())); + remoteProxyConnector.setRemote(new URI("fanout:static://" + getLocalURI())); + service.addProxyConnector(remoteProxyConnector); + + return service; + } + + protected void setUp() throws Exception { + super.setUp(); + remoteBroker = createRemoteBroker(); + remoteBroker.start(); + } + + protected void tearDown() throws Exception { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + StubConnection connection = iter.next(); + connection.stop(); + iter.remove(); + } + remoteBroker.stop(); + super.tearDown(); + } + + protected String getRemoteURI() { + return "tcp://localhost:6171"; + } + + protected String getLocalURI() { + return "tcp://localhost:6161"; + } + + protected String getRemoteProxyURI() { + return "tcp://localhost:6162"; + } + + protected String getLocalProxyURI() { + return "tcp://localhost:6172"; + } + + protected StubConnection createConnection() throws Exception { + Transport transport = TransportFactory.connect(connector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + protected StubConnection createRemoteConnection() throws Exception { + Transport transport = TransportFactory.connect(remoteConnector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + protected StubConnection createProxyConnection() throws Exception { + Transport transport = TransportFactory.connect(proxyConnector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + protected StubConnection createRemoteProxyConnection() throws Exception { + Transport transport = TransportFactory.connect(remoteProxyConnector.getServer().getConnectURI()); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AMQauth.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AMQauth.ldif new file mode 100644 index 0000000000..45d8ae0ce5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AMQauth.ldif @@ -0,0 +1,159 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +dn: o=ActiveMQ,ou=system +objectclass: organization +objectclass: top +o: ActiveMQ + +dn: ou=users,o=ActiveMQ,ou=system +objectclass: organizationalUnit +objectclass: top +ou: users + +dn: uid=ngcutura,ou=users,o=ActiveMQ,ou=system +objectclass: inetOrgPerson +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Goran Cutura +sn: Cutura +uid: ngcutura +userpassword:: e3NoYX0wZE9sTGxnU2ZRT3NSaFR5OGx3NUM3K1hlSkE9 + +dn: cn=roles,uid=ngcutura,ou=users,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: roles +uniquemember: uid=ngcutura + +dn: ou=destinations,o=ActiveMQ,ou=system +objectclass: organizationalUnit +objectclass: top +ou: destinations + +dn: ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: organizationalUnit +objectclass: top +ou: topics + +dn: uid=topic1,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: uidObject +objectclass: top +objectclass: applicationProcess +uid: topic1 +cn: topic1 + +dn: cn=admin,uid=topic1,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: admin +uniquemember: uid=role1 + +dn: cn=read,uid=topic1,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: read +uniquemember: uid=role2 + +dn: cn=write,uid=topic1,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: write +uniquemember: uid=role3 + +dn: ou=queues,ou=destinations,o=ActiveMQ,ou=system +objectclass: organizationalUnit +objectclass: top +ou: queues + +dn: uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system +objectclass: applicationProcess +objectclass: uidObject +objectclass: top +uid: queue1 +cn: queue1 + +dn: cn=read,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: read +uniquemember: uid=role1 + +dn: cn=write,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: write +uniquemember: uid=role1 +uniquemember: uid=role2 + +dn: cn=admin,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: admin +uniquemember: uid=role1 + +dn: uid=ActiveMQ.Advisory,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: uidObject +objectclass: top +objectclass: applicationProcess +uid: ActiveMQ.Advisory +cn: ActiveMQ.Advisory + +dn: cn=admin,uid=ActiveMQ.Advisory,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: admin +uniquemember: uid=role1 + +dn: cn=read,uid=ActiveMQ.Advisory,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: read +uniquemember: uid=role2 + +dn: cn=write,uid=ActiveMQ.Advisory,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: write +uniquemember: uid=role3 + +dn: uid=ActiveMQ.Temp,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: uidObject +objectclass: top +objectclass: applicationProcess +uid: ActiveMQ.Temp +cn: ActiveMQ.Temp + +dn: cn=admin,uid=ActiveMQ.Temp,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: admin +uniquemember: uid=role1 + +dn: cn=read,uid=ActiveMQ.Temp,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: read +uniquemember: uid=role2 + +dn: cn=write,uid=ActiveMQ.Temp,ou=topics,ou=destinations,o=ActiveMQ,ou=system +objectclass: groupOfUniqueNames +objectclass: top +cn: write +uniquemember: uid=role3 + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AbstractCachedLDAPAuthorizationMapLegacyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AbstractCachedLDAPAuthorizationMapLegacyTest.java new file mode 100644 index 0000000000..86165f5fe7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AbstractCachedLDAPAuthorizationMapLegacyTest.java @@ -0,0 +1,434 @@ +/** + * 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.security; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.naming.Context; +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.directory.DirContext; + +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.jaas.GroupPrincipal; +import org.apache.activemq.util.Wait; +import org.apache.directory.ldap.client.api.LdapConnection; +import org.apache.directory.server.core.integ.AbstractLdapTestUnit; +import org.apache.directory.shared.ldap.model.ldif.LdifEntry; +import org.apache.directory.shared.ldap.model.ldif.LdifReader; +import org.apache.directory.shared.ldap.model.message.ModifyRequest; +import org.apache.directory.shared.ldap.model.message.ModifyRequestImpl; +import org.apache.directory.shared.ldap.model.name.Dn; +import org.apache.directory.shared.ldap.model.name.Rdn; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public abstract class AbstractCachedLDAPAuthorizationMapLegacyTest extends AbstractLdapTestUnit { + + static final GroupPrincipal GUESTS = new GroupPrincipal("guests"); + static final GroupPrincipal USERS = new GroupPrincipal("users"); + static final GroupPrincipal ADMINS = new GroupPrincipal("admins"); + + protected LdapConnection connection; + protected SimpleCachedLDAPAuthorizationMap map; + + @Before + public void setup() throws Exception { + connection = getLdapConnection(); + map = createMap(); + } + + @After + public void cleanup() throws Exception { + if (connection != null) { + try { + connection.close(); + } catch (IOException e) { + // Ignore + } + } + + if (map != null) { + map.destroy(); + } + } + + @Test + public void testQuery() throws Exception { + map.query(); + Set readACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + readACLs, 2, readACLs.size()); + assertTrue("Contains admin group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + + Set failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + } + + @Test + public void testSynchronousUpdate() throws Exception { + map.setRefreshInterval(1); + map.query(); + Set readACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + readACLs, 2, readACLs.size()); + assertTrue("Contains admin group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + + Set failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + + LdifReader reader = new LdifReader(getRemoveLdif()); + + for (LdifEntry entry : reader) { + connection.delete(entry.getDn()); + } + + reader.close(); + + assertTrue("did not get expected size. ", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return map.getReadACLs(new ActiveMQQueue("TEST.FOO")).size() == 0; + } + })); + + assertNull(map.getTempDestinationReadACLs()); + assertNull(map.getTempDestinationWriteACLs()); + assertNull(map.getTempDestinationAdminACLs()); + } + + @Test + public void testWildcards() throws Exception { + map.query(); + Set fooACLs = map.getReadACLs(new ActiveMQQueue("FOO.1")); + assertEquals("set size: " + fooACLs, 2, fooACLs.size()); + assertTrue("Contains admin group", fooACLs.contains(ADMINS)); + assertTrue("Contains users group", fooACLs.contains(USERS)); + + Set barACLs = map.getReadACLs(new ActiveMQQueue("BAR.2")); + assertEquals("set size: " + barACLs, 2, barACLs.size()); + assertTrue("Contains admin group", barACLs.contains(ADMINS)); + assertTrue("Contains users group", barACLs.contains(USERS)); + } + + @Test + public void testAdvisory() throws Exception { + map.query(); + Set readACLs = map.getReadACLs(new ActiveMQTopic("ActiveMQ.Advisory.Connection")); + assertEquals("set size: " + readACLs, 2, readACLs.size()); + assertTrue("Contains admin group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + } + + @Test + public void testTemporary() throws Exception { + map.query(); + + Thread.sleep(1000); + Set readACLs = map.getTempDestinationReadACLs(); + assertEquals("set size: " + readACLs, 2, readACLs.size()); + assertTrue("Contains admin group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + } + + @Test + public void testAdd() throws Exception { + map.query(); + + Set failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + + LdifReader reader = new LdifReader(getAddLdif()); + + for (LdifEntry entry : reader) { + connection.add(entry.getEntry()); + } + + reader.close(); + + Thread.sleep(2000); + + failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + } + + @Test + public void testRemove() throws Exception { + map.query(); + + Set failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + + LdifReader reader = new LdifReader(getRemoveLdif()); + + for (LdifEntry entry : reader) { + connection.delete(entry.getDn()); + } + + reader.close(); + Thread.sleep(2000); + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + + assertTrue(map.getTempDestinationReadACLs() == null || map.getTempDestinationReadACLs().isEmpty()); + assertTrue(map.getTempDestinationWriteACLs() == null || map.getTempDestinationWriteACLs().isEmpty()); + assertTrue(map.getTempDestinationAdminACLs() == null || map.getTempDestinationAdminACLs().isEmpty()); + } + + @Test + public void testRenameDestination() throws Exception { + map.query(); + + // Test for a destination rename + Set failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + + connection.rename(new Dn("cn=TEST.FOO," + getQueueBaseDn()), + new Rdn("cn=TEST.BAR")); + + Thread.sleep(2000); + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.BAR")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + } + + @Test + public void testRenamePermission() throws Exception { + map.query(); + + // Test for a permission rename + connection.delete(new Dn("cn=Read,cn=TEST.FOO," + getQueueBaseDn())); + + Thread.sleep(2000); + + Set failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + + failedACLs = map.getWriteACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + + connection.rename(new Dn("cn=Write,cn=TEST.FOO," + getQueueBaseDn()), + new Rdn("cn=Read")); + + Thread.sleep(2000); + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + + failedACLs = map.getWriteACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + } + + @Test + public void testChange() throws Exception { + map.query(); + + // Change permission entry + Set failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + + Dn dn = new Dn("cn=read,cn=TEST.FOO," + getQueueBaseDn()); + + ModifyRequest request = new ModifyRequestImpl(); + request.setName(dn); + setupModifyRequest(request); + + connection.modify(request); + + Thread.sleep(2000); + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 1, failedACLs.size()); + + // Change destination entry + request = new ModifyRequestImpl(); + request.setName(new Dn("cn=TEST.FOO," + getQueueBaseDn())); + request.add("description", "This is a description! In fact, it is a very good description."); + + connection.modify(request); + + Thread.sleep(2000); + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 1, failedACLs.size()); + } + + @Test + public void testRestartAsync() throws Exception { + testRestart(false); + } + + @Test + public void testRestartSync() throws Exception { + testRestart(true); + } + + public void testRestart(final boolean sync) throws Exception { + if (sync) { + // ldap connection can be slow to close + map.setRefreshInterval(1000); + } + map.query(); + + Set failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + + getLdapServer().stop(); + + // wait for the context to be closed + // as we can't rely on ldar server isStarted() + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + if (sync) { + return !map.isContextAlive(); + } else { + return map.context == null; + } + } + }); + + failedACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOO")); + assertEquals("set size: " + failedACLs, 2, failedACLs.size()); + + getLdapServer().start(); + + Thread.sleep(2000); + + connection = getLdapConnection(); + + LdifReader reader = new LdifReader(getAddLdif()); + + for (LdifEntry entry : reader) { + connection.add(entry.getEntry()); + } + + reader.close(); + + assertTrue("did not get expected size. ", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return map.getReadACLs(new ActiveMQQueue("FAILED")).size() == 2; + } + })); + } + + protected SimpleCachedLDAPAuthorizationMap createMap() { + return new SimpleCachedLDAPAuthorizationMap(); + } + + protected abstract InputStream getAddLdif(); + + protected abstract InputStream getRemoveLdif(); + + protected void setupModifyRequest(ModifyRequest request) { + request.remove("member", "cn=users"); + } + + protected abstract String getQueueBaseDn(); + + protected abstract LdapConnection getLdapConnection() throws Exception; + + public static void cleanAndLoad(String deleteFromDn, String ldifResourcePath, + String ldapHost, int ldapPort, String ldapUser, String ldapPass, + DirContext context) throws Exception { + // Cleanup everything used for testing. + List dns = new LinkedList(); + dns.add(deleteFromDn); + + while (!dns.isEmpty()) { + String name = dns.get(dns.size() - 1); + Context currentContext = (Context) context.lookup(name); + NamingEnumeration namingEnum = currentContext.list(""); + + if (namingEnum.hasMore()) { + while (namingEnum.hasMore()) { + dns.add(namingEnum.next().getNameInNamespace()); + } + } else { + context.unbind(name); + dns.remove(dns.size() - 1); + } + } + + // A bit of a hacked approach to loading an LDIF into OpenLDAP since there isn't an easy way to do it + // otherwise. This approach invokes the command line tool programmatically but has + // to short-circuit the call to System.exit that the command line tool makes when it finishes. + // We are assuming that there isn't already a security manager in place. + final SecurityManager securityManager = new SecurityManager() { + + @Override + public void checkPermission(java.security.Permission permission) { + if (permission.getName().contains("exitVM")) { + throw new SecurityException("System.exit calls disabled for the moment."); + } + } + }; + + System.setSecurityManager(securityManager); + + + File file = new File(AbstractCachedLDAPAuthorizationMapLegacyTest.class.getClassLoader().getResource( + ldifResourcePath).toURI()); + + Class clazz = Class.forName("LDAPModify"); + Method mainMethod = clazz.getMethod("main", String[].class); + + try { + mainMethod.invoke(null, new Object[] { + new String[] { + "-v", + "-h", ldapHost, + "-p", String.valueOf(ldapPort), + "-D", ldapUser, + "-w", ldapPass, + "-a", + "-f", file.toString()}}); + } catch (InvocationTargetException e) { + if (!(e.getTargetException() instanceof SecurityException)) { + throw e; + } + } + + System.setSecurityManager(null); + } +} + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AbstractCachedLDAPAuthorizationModuleTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AbstractCachedLDAPAuthorizationModuleTest.java new file mode 100644 index 0000000000..3f52ed3ee8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AbstractCachedLDAPAuthorizationModuleTest.java @@ -0,0 +1,63 @@ +/** + * 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.security; + +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.jaas.UserPrincipal; +import org.apache.directory.shared.ldap.model.message.ModifyRequest; +import org.junit.Test; + +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public abstract class AbstractCachedLDAPAuthorizationModuleTest + extends AbstractCachedLDAPAuthorizationMapLegacyTest { + + static final UserPrincipal JDOE = new UserPrincipal("jdoe"); + + @Test + public void testQuery() throws Exception { + map.query(); + Set readACLs = map.getReadACLs(new ActiveMQQueue("TEST.FOOBAR")); + assertEquals("set size: " + readACLs, 3, readACLs.size()); + assertTrue("Contains admin group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + assertTrue("Contains jdoe user", readACLs.contains(JDOE)); + + Set failedACLs = map.getReadACLs(new ActiveMQQueue("FAILED")); + assertEquals("set size: " + failedACLs, 0, failedACLs.size()); + + super.testQuery(); + } + + @Override + protected final void setupModifyRequest(ModifyRequest request) { + request.remove("member", getMemberAttributeValueForModifyRequest()); + } + + protected abstract String getMemberAttributeValueForModifyRequest(); + + @Override + protected SimpleCachedLDAPAuthorizationMap createMap() { + SimpleCachedLDAPAuthorizationMap map = super.createMap(); + map.setLegacyGroupMapping(false); + return map; + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AuthorizationMapTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AuthorizationMapTest.java new file mode 100644 index 0000000000..b6ace87282 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/AuthorizationMapTest.java @@ -0,0 +1,194 @@ +/** + * 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.security; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.filter.DestinationMapEntry; +import org.apache.activemq.jaas.GroupPrincipal; + +/** + * + * + */ +public class AuthorizationMapTest extends TestCase { + static final GroupPrincipal USERS = new GroupPrincipal("users"); + static final GroupPrincipal ADMINS = new GroupPrincipal("admins"); + static final GroupPrincipal TEMP_DESTINATION_ADMINS = new GroupPrincipal("tempDestAdmins"); + + public void testAuthorizationMap() { + AuthorizationMap map = createAuthorizationMap(); + + Set readACLs = map.getReadACLs(new ActiveMQQueue("USERS.FOO.BAR")); + assertEquals("set size: " + readACLs, 2, readACLs.size()); + assertTrue("Contains users group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + + } + + public void testCompositeDoesNotBypassAuthorizationMap() { + AuthorizationMap map = createAuthorizationMap(); + + Set readACLs = map.getReadACLs(new ActiveMQQueue("USERS.FOO.BAR,DENIED")); + assertEquals("set size: " + readACLs, 1, readACLs.size()); + assertTrue("Contains users group", readACLs.contains(ADMINS)); + } + + public void testAuthorizationMapWithTempDest() { + AuthorizationMap map = createAuthorizationMapWithTempDest(); + + Set readACLs = map.getReadACLs(new ActiveMQQueue("USERS.FOO.BAR")); + assertEquals("set size: " + readACLs, 2, readACLs.size()); + assertTrue("Contains users group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + + Set tempAdminACLs = map.getTempDestinationAdminACLs(); + assertEquals("set size: " + tempAdminACLs, 1, tempAdminACLs.size()); + assertTrue("Contains users group", tempAdminACLs.contains(TEMP_DESTINATION_ADMINS)); + + } + + public void testWildcards() { + AuthorizationMap map = createWildcardAuthorizationMap(); + + Set readACLs = map.getReadACLs(new ActiveMQQueue("USERS.FOO.BAR")); + assertEquals("set size: " + readACLs, 1, readACLs.size()); + assertTrue("Contains users group", readACLs.contains(ADMINS)); + assertTrue("Contains users group", readACLs.contains(USERS)); + + Set writeAcls = map.getWriteACLs(new ActiveMQQueue("USERS.FOO.BAR")); + assertEquals("set size: " + writeAcls, 1, writeAcls.size()); + assertTrue("Contains users group", writeAcls.contains(ADMINS)); + assertTrue("Contains users group", writeAcls.contains(USERS)); + + Set adminAcls = map.getAdminACLs(new ActiveMQQueue("USERS.FOO.BAR")); + assertEquals("set size: " + adminAcls, 1, adminAcls.size()); + assertTrue("Contains users group", adminAcls.contains(ADMINS)); + assertFalse("Contains users group", adminAcls.contains(USERS)); + + Set tempAdminACLs = map.getTempDestinationAdminACLs(); + assertEquals("set size: " + tempAdminACLs, 1, tempAdminACLs.size()); + assertTrue("Contains users group", tempAdminACLs.contains(TEMP_DESTINATION_ADMINS)); + } + + protected AuthorizationMap createWildcardAuthorizationMap() { + DefaultAuthorizationMap answer = new DefaultAuthorizationMap(); + + List entries = new ArrayList(); + + AuthorizationEntry entry = new AuthorizationEntry(); + entry.setQueue(">"); + try { + entry.setRead("*"); + entry.setWrite("*"); + entry.setAdmin("admins"); + } catch (Exception e) { + fail(e.toString()); + } + + entries.add(entry); + + answer.setAuthorizationEntries(entries); + + TempDestinationAuthorizationEntry tEntry = new TempDestinationAuthorizationEntry(); + try { + tEntry.setAdmin("*"); + } catch (Exception e) { + fail(e.toString()); + } + + answer.setTempDestinationAuthorizationEntry(tEntry); + + return answer; + + } + + @SuppressWarnings("rawtypes") + protected AuthorizationMap createAuthorizationMap() { + DefaultAuthorizationMap answer = new DefaultAuthorizationMap(); + + List entries = new ArrayList(); + + AuthorizationEntry entry = new AuthorizationEntry(); + entry.setGroupClass("org.apache.activemq.jaas.GroupPrincipal"); + entry.setQueue(">"); + try { + entry.setRead("admins"); + } catch (Exception e) { + fail(e.toString()); + } + + entries.add(entry); + // entry using default org.apache.activemq.jaas.GroupPrincipal class + entry = new AuthorizationEntry(); + entry.setQueue("USERS.>"); + try { + entry.setRead("users"); + } catch (Exception e) { + fail(e.toString()); + } + entries.add(entry); + + answer.setAuthorizationEntries(entries); + + return answer; + } + + @SuppressWarnings("rawtypes") + protected AuthorizationMap createAuthorizationMapWithTempDest() { + DefaultAuthorizationMap answer = new DefaultAuthorizationMap(); + + List entries = new ArrayList(); + + AuthorizationEntry entry = new AuthorizationEntry(); + entry.setQueue(">"); + try { + entry.setRead("admins"); + } catch (Exception e) { + fail(e.toString()); + } + entries.add(entry); + + entry = new AuthorizationEntry(); + entry.setQueue("USERS.>"); + try { + entry.setRead("users"); + } catch (Exception e) { + fail(e.toString()); + } + entries.add(entry); + + answer.setAuthorizationEntries(entries); + + // create entry for temporary queue + TempDestinationAuthorizationEntry tEntry = new TempDestinationAuthorizationEntry(); + try { + tEntry.setAdmin("tempDestAdmins"); + } catch (Exception e) { + fail(e.toString()); + } + + answer.setTempDestinationAuthorizationEntry(tEntry); + + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleLegacyOpenLDAPTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleLegacyOpenLDAPTest.java new file mode 100644 index 0000000000..5c2764a21c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleLegacyOpenLDAPTest.java @@ -0,0 +1,97 @@ +/** + * 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.security; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.directory.ldap.client.api.LdapConnection; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.apache.directory.shared.ldap.model.exception.LdapException; +import org.apache.directory.shared.ldap.model.name.Dn; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test of the {@link SimpleCachedLDAPAuthorizationMap} that tests against a basic OpenLDAP instance. + * Disabled by default because it requires external setup to provide the OpenLDAP instance. + * + * To enable, you need an OpenLDAP with a minimum of the following in the slapd.conf file: + * + * suffix "dc=apache,dc=org" + * rootdn "cn=Manager,dc=apache,dc=org" + * rootpw {SSHA}+Rx8kj98q3FlK5rUkT2hAtMP5v2ImQ82 + * + * If you wish to use different settings or don't use the default port, change the constants + * below for your environment. + */ +@Ignore +public class CachedLDAPAuthorizationModuleLegacyOpenLDAPTest extends + AbstractCachedLDAPAuthorizationMapLegacyTest { + + protected static final String LDAP_USER = "cn=Manager,dc=apache,dc=org"; + protected static final String LDAP_PASS = "password"; + protected static final String LDAP_HOST = "localhost"; + protected static final int LDAP_PORT = 389; + + @Before + @Override + public void setup() throws Exception { + + super.setup(); + + cleanAndLoad("dc=apache,dc=org", "org/apache/activemq/security/activemq-openldap-legacy.ldif", + LDAP_HOST, LDAP_PORT, LDAP_USER, LDAP_PASS, map.open()); + } + + @Test + public void testRenameDestination() throws Exception { + // Subtree rename not implemented by OpenLDAP. + } + + protected SimpleCachedLDAPAuthorizationMap createMap() { + SimpleCachedLDAPAuthorizationMap newMap = super.createMap(); + newMap.setConnectionURL("ldap://" + LDAP_HOST + ":" + String.valueOf(LDAP_PORT)); + newMap.setConnectionUsername(LDAP_USER); + newMap.setConnectionPassword(LDAP_PASS); + // Persistent search is not supported in OpenLDAP + newMap.setRefreshInterval(10); + newMap.setQueueSearchBase("ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"); + newMap.setTopicSearchBase("ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"); + newMap.setTempSearchBase("ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"); + return newMap; + } + + protected InputStream getAddLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-openldap-legacy-add.ldif"); + } + + protected InputStream getRemoveLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-openldap-legacy-delete.ldif"); + } + + protected String getQueueBaseDn() { + return "ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"; + } + + protected LdapConnection getLdapConnection() throws LdapException, IOException { + LdapConnection connection = new LdapNetworkConnection(LDAP_HOST, LDAP_PORT); + connection.bind(new Dn(LDAP_USER), LDAP_PASS); + return connection; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleLegacyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleLegacyTest.java new file mode 100644 index 0000000000..f696cb306f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleLegacyTest.java @@ -0,0 +1,65 @@ +/** + * 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.security; + +import org.apache.directory.ldap.client.api.LdapConnection; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.apache.directory.shared.ldap.model.exception.LdapException; +import org.apache.directory.shared.ldap.model.name.Dn; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.io.InputStream; + + +@RunWith( FrameworkRunner.class ) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")}) +@ApplyLdifFiles( + "org/apache/activemq/security/activemq-apacheds-legacy.ldif" +) +public class CachedLDAPAuthorizationModuleLegacyTest extends AbstractCachedLDAPAuthorizationMapLegacyTest { + + @Override + protected SimpleCachedLDAPAuthorizationMap createMap() { + SimpleCachedLDAPAuthorizationMap map = super.createMap(); + map.setConnectionURL("ldap://localhost:" + getLdapServer().getPort()); + return map; + } + + protected InputStream getAddLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-apacheds-legacy-add.ldif"); + } + + protected InputStream getRemoveLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-apacheds-legacy-delete.ldif"); + } + + protected String getQueueBaseDn() { + return "ou=Queue,ou=Destination,ou=ActiveMQ,ou=system"; + } + + protected LdapConnection getLdapConnection() throws LdapException, IOException { + LdapConnection connection = new LdapNetworkConnection("localhost", getLdapServer().getPort()); + connection.bind(new Dn("uid=admin,ou=system"), "secret"); + return connection; + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleOpenLDAPTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleOpenLDAPTest.java new file mode 100644 index 0000000000..6d0ca9339d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleOpenLDAPTest.java @@ -0,0 +1,106 @@ +/** + * 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.security; + +import org.apache.directory.ldap.client.api.LdapConnection; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.apache.directory.shared.ldap.model.exception.LdapException; +import org.apache.directory.shared.ldap.model.name.Dn; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Test of the {@link SimpleCachedLDAPAuthorizationMap} that tests against a basic OpenLDAP instance. + * Disabled by default because it requires external setup to provide the OpenLDAP instance. + * + * To enable, you need an OpenLDAP with a minimum of the following in the slapd.conf file: + * + * suffix "dc=apache,dc=org" + * rootdn "cn=Manager,dc=apache,dc=org" + * rootpw {SSHA}+Rx8kj98q3FlK5rUkT2hAtMP5v2ImQ82 + * + * If you wish to use different settings or don't use the default port, change the constants + * below for your environment. + */ +@Ignore +public class CachedLDAPAuthorizationModuleOpenLDAPTest extends AbstractCachedLDAPAuthorizationModuleTest { + + protected static final String LDAP_USER = "cn=Manager,dc=apache,dc=org"; + protected static final String LDAP_PASS = "password"; + protected static final String LDAP_HOST = "localhost"; + protected static final int LDAP_PORT = 389; + + @Before + @Override + public void setup() throws Exception { + + super.setup(); + + cleanAndLoad("dc=apache,dc=org", "org/apache/activemq/security/activemq-openldap.ldif", + LDAP_HOST, LDAP_PORT, LDAP_USER, LDAP_PASS, map.open()); + } + + @Test + public void testRenameDestination() throws Exception { + // Subtree rename not implemented by OpenLDAP. + } + + @Override + protected SimpleCachedLDAPAuthorizationMap createMap() { + SimpleCachedLDAPAuthorizationMap newMap = super.createMap(); + newMap.setConnectionURL("ldap://" + LDAP_HOST + ":" + String.valueOf(LDAP_PORT)); + newMap.setConnectionUsername(LDAP_USER); + newMap.setConnectionPassword(LDAP_PASS); + // Persistent search is not supported in OpenLDAP + newMap.setRefreshInterval(10); + newMap.setQueueSearchBase("ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"); + newMap.setTopicSearchBase("ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"); + newMap.setTempSearchBase("ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"); + return newMap; + } + + @Override + protected InputStream getAddLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-openldap-add.ldif"); + } + + @Override + protected InputStream getRemoveLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-openldap-delete.ldif"); + } + + @Override + protected String getMemberAttributeValueForModifyRequest() { + return "cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"; + } + + @Override + protected String getQueueBaseDn() { + return "ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org"; + } + + @Override + protected LdapConnection getLdapConnection() throws LdapException, IOException { + LdapConnection connection = new LdapNetworkConnection(LDAP_HOST, LDAP_PORT); + connection.bind(new Dn(LDAP_USER), LDAP_PASS); + return connection; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleTest.java new file mode 100644 index 0000000000..5d6f2e734f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPAuthorizationModuleTest.java @@ -0,0 +1,71 @@ +/** + * 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.security; + +import org.apache.directory.ldap.client.api.LdapConnection; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.apache.directory.shared.ldap.model.name.Dn; +import org.junit.runner.RunWith; + +import java.io.InputStream; + + +@RunWith( FrameworkRunner.class ) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")}) +@ApplyLdifFiles( + "org/apache/activemq/security/activemq-apacheds.ldif" +) +public class CachedLDAPAuthorizationModuleTest extends AbstractCachedLDAPAuthorizationModuleTest { + + @Override + protected SimpleCachedLDAPAuthorizationMap createMap() { + SimpleCachedLDAPAuthorizationMap map = super.createMap(); + map.setConnectionURL("ldap://localhost:" + getLdapServer().getPort()); + return map; + } + + @Override + protected InputStream getAddLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-apacheds-add.ldif"); + } + + @Override + protected InputStream getRemoveLdif() { + return getClass().getClassLoader().getResourceAsStream("org/apache/activemq/security/activemq-apacheds-delete.ldif"); + } + + @Override + protected String getMemberAttributeValueForModifyRequest() { + return "cn=users,ou=Group,ou=ActiveMQ,ou=system"; + } + + protected String getQueueBaseDn() { + return "ou=Queue,ou=Destination,ou=ActiveMQ,ou=system"; + } + + @Override + protected LdapConnection getLdapConnection() throws Exception { + LdapConnection connection = new LdapNetworkConnection("localhost", getLdapServer().getPort()); + connection.bind(new Dn("uid=admin,ou=system"), "secret"); + return connection; + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPSecurityLegacyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPSecurityLegacyTest.java new file mode 100644 index 0000000000..43ff99ce5e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPSecurityLegacyTest.java @@ -0,0 +1,129 @@ +/** + * 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.security; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.AbstractLdapTestUnit; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.apache.directory.server.ldap.LdapServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.jms.*; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + + +@RunWith( FrameworkRunner.class ) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")}) +@ApplyLdifFiles( + "org/apache/activemq/security/activemq-apacheds-legacy.ldif" +) +public class CachedLDAPSecurityLegacyTest extends AbstractLdapTestUnit { + + public BrokerService broker; + + public static LdapServer ldapServer; + + @Before + public void setup() throws Exception { + System.setProperty("ldapPort", String.valueOf(getLdapServer().getPort())); + + broker = BrokerFactory.createBroker("xbean:org/apache/activemq/security/activemq-apacheds-legacy.xml"); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void shutdown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testSendReceive() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createQueue("TEST.FOO"); + + MessageProducer producer = sess.createProducer(queue); + MessageConsumer consumer = sess.createConsumer(queue); + + producer.send(sess.createTextMessage("test")); + Message msg = consumer.receive(1000); + assertNotNull(msg); + } + + @Test + public void testSendDenied() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createQueue("ADMIN.FOO"); + + try { + sess.createProducer(queue); + fail("expect auth exception"); + } catch (JMSException expected) { + } + } + + @Test + public void testCompositeSendDenied() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createQueue("TEST.FOO,ADMIN.FOO"); + + try { + sess.createProducer(queue); + fail("expect auth exception"); + } catch (JMSException expected) { + } + } + + @Test + public void testTempDestinations() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createTemporaryQueue(); + + MessageProducer producer = sess.createProducer(queue); + MessageConsumer consumer = sess.createConsumer(queue); + + producer.send(sess.createTextMessage("test")); + Message msg = consumer.receive(1000); + assertNotNull(msg); + } + +} + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPSecurityTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPSecurityTest.java new file mode 100644 index 0000000000..ec22095833 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/CachedLDAPSecurityTest.java @@ -0,0 +1,45 @@ +/** + * 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.security; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.junit.Before; +import org.junit.runner.RunWith; + +@RunWith( FrameworkRunner.class ) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")}) +@ApplyLdifFiles( + "org/apache/activemq/security/activemq-apacheds.ldif" +) +public class CachedLDAPSecurityTest extends CachedLDAPSecurityLegacyTest { + + @Before + @Override + public void setup() throws Exception { + System.setProperty("ldapPort", String.valueOf(getLdapServer().getPort())); + + broker = BrokerFactory.createBroker("xbean:org/apache/activemq/security/activemq-apacheds.xml"); + broker.start(); + broker.waitUntilStarted(); + } +} + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/DoSTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/DoSTest.java new file mode 100644 index 0000000000..c236822bd9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/DoSTest.java @@ -0,0 +1,100 @@ +/** + * 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.security; + +import java.net.URI; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.JMSException; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The configuration is set to except a maximum of 2 concurrent connections + * As the exception is deliberately ignored, the ActiveMQConnection would continue to + * attempt to connect unless the connection's transport was also stopped on an error. + *

+ * As the maximum connections allowed is 2, no more connections would be allowed unless + * the transport was adequately destroyed on the broker side. + */ + +public class DoSTest extends JmsTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(DoSTest.class); + + public void testInvalidAuthentication() throws Throwable { + + // with failover reconnect, we don't expect this thread to complete + // but periodically the failure changes from ExceededMaximumConnectionsException on the broker + // side to a SecurityException. + // A failed to authenticated but idle connection (dos style) is aborted by the inactivity monitor + // since useKeepAlive=false + + final AtomicBoolean done = new AtomicBoolean(false); + Thread thread = new Thread() { + Connection connection = null; + + public void run() { + for (int i = 0; i < 1000 && !done.get(); i++) { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(); + try { + // Bad password + connection = factory.createConnection("bad", "krap"); + connection.start(); + fail("Expected exception."); + } catch (JMSException e) { + // ignore exception and don't close + e.printStackTrace(); + } + } + } + }; + + thread.start(); + + // run dos for a while + TimeUnit.SECONDS.sleep(10); + + LOG.info("trying genuine connection ..."); + // verify a valid connection can work with one of the 2 allowed connections provided it is eager! + // it could take a while as it is competing with the three other reconnect threads. + // wonder if it makes sense to serialise these reconnect attempts on an executor + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("failover:(tcp://127.0.0.1:61616)?useExponentialBackOff=false&reconnectDelay=10"); + Connection goodConnection = factory.createConnection("user", "password"); + goodConnection.start(); + goodConnection.close(); + + LOG.info("giving up on DOS"); + done.set(true); + } + + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/dos-broker.xml"); + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasCertificateAuthenticationBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasCertificateAuthenticationBrokerTest.java new file mode 100644 index 0000000000..6aa62f7a2e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasCertificateAuthenticationBrokerTest.java @@ -0,0 +1,187 @@ +/** + * 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.security; + +import java.security.Principal; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.StubBroker; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.jaas.GroupPrincipal; +import org.apache.activemq.jaas.UserPrincipal; +import org.apache.activemq.transport.tcp.StubX509Certificate; + +public class JaasCertificateAuthenticationBrokerTest extends TestCase { + StubBroker receiveBroker; + + JaasCertificateAuthenticationBroker authBroker; + + ConnectionContext connectionContext; + ConnectionInfo connectionInfo; + + @Override + protected void setUp() throws Exception { + receiveBroker = new StubBroker(); + + authBroker = new JaasCertificateAuthenticationBroker(receiveBroker, ""); + + connectionContext = new ConnectionContext(); + connectionInfo = new ConnectionInfo(); + + connectionInfo.setTransportContext(new StubX509Certificate[] {}); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + private void setConfiguration(Set userNames, Set groupNames, boolean loginShouldSucceed) { + HashMap configOptions = new HashMap(); + + String userNamesString; + { + Iterator iter = userNames.iterator(); + userNamesString = "" + (iter.hasNext() ? iter.next() : ""); + while (iter.hasNext()) { + userNamesString += "," + iter.next(); + } + } + + String groupNamesString = ""; + { + Iterator iter = groupNames.iterator(); + groupNamesString = "" + (iter.hasNext() ? iter.next() : ""); + while (iter.hasNext()) { + groupNamesString += "," + iter.next(); + } + } + + configOptions.put(StubLoginModule.ALLOW_LOGIN_PROPERTY, loginShouldSucceed ? "true" : "false"); + configOptions.put(StubLoginModule.USERS_PROPERTY, userNamesString); + configOptions.put(StubLoginModule.GROUPS_PROPERTY, groupNamesString); + AppConfigurationEntry configEntry = new AppConfigurationEntry("org.apache.activemq.security.StubLoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + configOptions); + + StubJaasConfiguration jaasConfig = new StubJaasConfiguration(configEntry); + + Configuration.setConfiguration(jaasConfig); + } + + public void testAddConnectionSuccess() { + String dnUserName = "dnUserName"; + + HashSet userNames = new HashSet(); + userNames.add(dnUserName); + + HashSet groupNames = new HashSet(); + groupNames.add("testGroup1"); + groupNames.add("testGroup2"); + groupNames.add("tesetGroup3"); + + setConfiguration(userNames, groupNames, true); + + try { + authBroker.addConnection(connectionContext, connectionInfo); + } catch (Exception e) { + fail("Call to addConnection failed: " + e.getMessage()); + } + + assertEquals("Number of addConnection calls to underlying Broker must match number of calls made to " + "AuthenticationBroker.", 1, receiveBroker.addConnectionData.size()); + + ConnectionContext receivedContext = receiveBroker.addConnectionData.getFirst().connectionContext; + + assertEquals("The SecurityContext's userName must be set to that of the UserPrincipal.", dnUserName, receivedContext.getSecurityContext().getUserName()); + + Set receivedPrincipals = receivedContext.getSecurityContext().getPrincipals(); + + for (Iterator iter = receivedPrincipals.iterator(); iter.hasNext();) { + Principal currentPrincipal = iter.next(); + + if (currentPrincipal instanceof UserPrincipal) { + if (userNames.remove(currentPrincipal.getName())) { + // Nothing, we did good. + } else { + // Found an unknown userName. + fail("Unknown UserPrincipal found"); + } + } else if (currentPrincipal instanceof GroupPrincipal) { + if (groupNames.remove(currentPrincipal.getName())) { + // Nothing, we did good. + } else { + fail("Unknown GroupPrincipal found."); + } + } else { + fail("Unexpected Principal subclass found."); + } + } + + if (!userNames.isEmpty()) { + fail("Some usernames were not added as UserPrincipals"); + } + + if (!groupNames.isEmpty()) { + fail("Some group names were not added as GroupPrincipals"); + } + } + + public void testAddConnectionFailure() { + HashSet userNames = new HashSet(); + + HashSet groupNames = new HashSet(); + groupNames.add("testGroup1"); + groupNames.add("testGroup2"); + groupNames.add("tesetGroup3"); + + setConfiguration(userNames, groupNames, false); + + boolean connectFailed = false; + try { + authBroker.addConnection(connectionContext, connectionInfo); + } catch (SecurityException e) { + connectFailed = true; + } catch (Exception e) { + fail("Failed to connect for unexpected reason: " + e.getMessage()); + } + + if (!connectFailed) { + fail("Unauthenticated connection allowed."); + } + + assertEquals("Unauthenticated connection allowed.", true, receiveBroker.addConnectionData.isEmpty()); + } + + public void testRemoveConnection() throws Exception { + connectionContext.setSecurityContext(new StubSecurityContext()); + + authBroker.removeConnection(connectionContext, connectionInfo, new Throwable()); + + assertEquals("removeConnection should clear ConnectionContext.", null, connectionContext.getSecurityContext()); + + assertEquals("Incorrect number of calls to underlying broker were made.", 1, receiveBroker.removeConnectionData.size()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java new file mode 100644 index 0000000000..7d7f3b6e71 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java @@ -0,0 +1,216 @@ +/** + * 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.security; + +import java.net.URI; +import java.security.Principal; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; + +import javax.net.ssl.SSLServerSocket; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.Connector; +import org.apache.activemq.broker.StubBroker; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.jaas.GroupPrincipal; +import org.apache.activemq.jaas.UserPrincipal; +import org.apache.activemq.transport.tcp.SslTransportServer; +import org.apache.activemq.transport.tcp.StubSSLServerSocket; +import org.apache.activemq.transport.tcp.StubSSLSocketFactory; +import org.apache.activemq.transport.tcp.StubX509Certificate; +import org.apache.activemq.transport.tcp.TcpTransportServer; + +/** + * + */ +public class JaasDualAuthenticationBrokerTest extends TestCase { + + private static final String INSECURE_GROUP = "insecureGroup"; + private static final String INSECURE_USERNAME = "insecureUserName"; + private static final String DN_GROUP = "dnGroup"; + private static final String DN_USERNAME = "dnUserName"; + + StubBroker receiveBroker; + JaasDualAuthenticationBroker authBroker; + + ConnectionContext connectionContext; + ConnectionInfo connectionInfo; + + SslTransportServer sslTransportServer; + TcpTransportServer nonSslTransportServer; + + /** create a dual login config, for both SSL and non-SSL connections + * using the StubLoginModule + * + */ + void createLoginConfig() { + HashMap sslConfigOptions = new HashMap(); + HashMap configOptions = new HashMap(); + + sslConfigOptions.put(StubLoginModule.ALLOW_LOGIN_PROPERTY, "true"); + sslConfigOptions.put(StubLoginModule.USERS_PROPERTY, DN_USERNAME); + sslConfigOptions.put(StubLoginModule.GROUPS_PROPERTY, DN_GROUP); + AppConfigurationEntry sslConfigEntry = new AppConfigurationEntry("org.apache.activemq.security.StubLoginModule", + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, sslConfigOptions); + + configOptions.put(StubLoginModule.ALLOW_LOGIN_PROPERTY, "true"); + configOptions.put(StubLoginModule.USERS_PROPERTY, INSECURE_USERNAME); + configOptions.put(StubLoginModule.GROUPS_PROPERTY, INSECURE_GROUP); + AppConfigurationEntry configEntry = new AppConfigurationEntry("org.apache.activemq.security.StubLoginModule", + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, configOptions); + + StubDualJaasConfiguration jaasConfig = new StubDualJaasConfiguration(configEntry, sslConfigEntry); + + Configuration.setConfiguration(jaasConfig); + } + + @Override + protected void setUp() throws Exception { + receiveBroker = new StubBroker(); + + authBroker = new JaasDualAuthenticationBroker(receiveBroker, "activemq-domain", "activemq-ssl-domain"); + + connectionContext = new ConnectionContext(); + + SSLServerSocket sslServerSocket = new StubSSLServerSocket(); + StubSSLSocketFactory socketFactory = new StubSSLSocketFactory(sslServerSocket); + + try { + sslTransportServer = new SslTransportServer(null, new URI("ssl://localhost:61616?needClientAuth=true"), + socketFactory); + } catch (Exception e) { + fail("Unable to create SslTransportServer."); + } + sslTransportServer.setNeedClientAuth(true); + sslTransportServer.bind(); + + try { + nonSslTransportServer = new TcpTransportServer(null, new URI("tcp://localhost:61613"), socketFactory); + } catch (Exception e) { + fail("Unable to create TcpTransportServer."); + } + + + connectionInfo = new ConnectionInfo(); + + createLoginConfig(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + + public void testSecureConnector() { + Connector connector = new TransportConnector(sslTransportServer); + connectionContext.setConnector(connector); + connectionInfo.setTransportContext(new StubX509Certificate[] {}); + + try { + authBroker.addConnection(connectionContext, connectionInfo); + } catch (Exception e) { + fail("Call to addConnection failed: " + e.getMessage()); + } + + assertEquals("Number of addConnection calls to underlying Broker must match number of calls made to " + + "AuthenticationBroker.", 1, receiveBroker.addConnectionData.size()); + + ConnectionContext receivedContext = receiveBroker.addConnectionData.getFirst().connectionContext; + + assertEquals("The SecurityContext's userName must be set to that of the UserPrincipal.", + DN_USERNAME, receivedContext.getSecurityContext().getUserName()); + + Set receivedPrincipals = receivedContext.getSecurityContext().getPrincipals(); + + + assertEquals("2 Principals received", 2, receivedPrincipals.size()); + + for (Iterator iter = receivedPrincipals.iterator(); iter.hasNext();) { + Principal currentPrincipal = iter.next(); + + if (currentPrincipal instanceof UserPrincipal) { + assertEquals("UserPrincipal is '" + DN_USERNAME + "'", DN_USERNAME, currentPrincipal.getName()); + } else if (currentPrincipal instanceof GroupPrincipal) { + assertEquals("GroupPrincipal is '" + DN_GROUP + "'", DN_GROUP, currentPrincipal.getName()); + } else { + fail("Unexpected Principal subclass found."); + } + } + + try { + authBroker.removeConnection(connectionContext, connectionInfo, null); + } catch (Exception e) { + fail("Call to removeConnection failed: " + e.getMessage()); + } + assertEquals("Number of removeConnection calls to underlying Broker must match number of calls made to " + + "AuthenticationBroker.", 1, receiveBroker.removeConnectionData.size()); + } + + public void testInsecureConnector() { + Connector connector = new TransportConnector(nonSslTransportServer); + connectionContext.setConnector(connector); + connectionInfo.setUserName(INSECURE_USERNAME); + + try { + authBroker.addConnection(connectionContext, connectionInfo); + } catch (Exception e) { + fail("Call to addConnection failed: " + e.getMessage()); + } + + assertEquals("Number of addConnection calls to underlying Broker must match number of calls made to " + + "AuthenticationBroker.", 1, receiveBroker.addConnectionData.size()); + + ConnectionContext receivedContext = receiveBroker.addConnectionData.getFirst().connectionContext; + + assertEquals("The SecurityContext's userName must be set to that of the UserPrincipal.", + INSECURE_USERNAME, receivedContext.getSecurityContext().getUserName()); + + Set receivedPrincipals = receivedContext.getSecurityContext().getPrincipals(); + + assertEquals("2 Principals received", 2, receivedPrincipals.size()); + for (Iterator iter = receivedPrincipals.iterator(); iter.hasNext();) { + Principal currentPrincipal = iter.next(); + + if (currentPrincipal instanceof UserPrincipal) { + assertEquals("UserPrincipal is '" + INSECURE_USERNAME + "'", + INSECURE_USERNAME, currentPrincipal.getName()); + } else if (currentPrincipal instanceof GroupPrincipal) { + assertEquals("GroupPrincipal is '" + INSECURE_GROUP + "'", + INSECURE_GROUP, currentPrincipal.getName()); + } else { + fail("Unexpected Principal subclass found."); + } + } + + try { + authBroker.removeConnection(connectionContext, connectionInfo, null); + } catch (Exception e) { + fail("Call to removeConnection failed: " + e.getMessage()); + } + assertEquals("Number of removeConnection calls to underlying Broker must match number of calls made to " + + "AuthenticationBroker.", 1, receiveBroker.removeConnectionData.size()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasNetworkTest.java new file mode 100644 index 0000000000..5c85cb602f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/JaasNetworkTest.java @@ -0,0 +1,85 @@ +/** + * 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.security; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +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.command.ActiveMQQueue; + +public class JaasNetworkTest extends TestCase { + + BrokerService broker1; + BrokerService broker2; + + public void setUp() throws Exception { + System.setProperty("java.security.auth.login.config", "src/test/resources/login.config"); + broker1 = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/security/broker1.xml")); + broker2 = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/security/broker2.xml")); + broker1.waitUntilStarted(); + broker2.waitUntilStarted(); + Thread.sleep(2000); + } + + protected void tearDown() throws Exception { + super.tearDown(); + broker1.stop(); + broker1.waitUntilStopped(); + broker2.stop(); + broker2.waitUntilStopped(); + } + + + + public void testNetwork() throws Exception { + + System.setProperty("javax.net.ssl.trustStore", "src/test/resources/org/apache/activemq/security/client.ts"); + System.setProperty("javax.net.ssl.trustStorePassword", "password"); + System.setProperty("javax.net.ssl.trustStoreType", "jks"); + System.setProperty("javax.net.ssl.keyStore", "src/test/resources/org/apache/activemq/security/client.ks"); + System.setProperty("javax.net.ssl.keyStorePassword", "password"); + System.setProperty("javax.net.ssl.keyStoreType", "jks"); + + ActiveMQConnectionFactory producerFactory = new ActiveMQConnectionFactory("ssl://localhost:61617"); + Connection producerConn = producerFactory.createConnection(); + Session producerSess = producerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSess.createProducer(new ActiveMQQueue("test")); + producerConn.start(); + TextMessage sentMessage = producerSess.createTextMessage("test"); + producer.send(sentMessage); + + ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory("ssl://localhost:61618"); + Connection consumerConn = consumerFactory.createConnection(); + Session consumerSess = consumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerConn.start(); + MessageConsumer consumer = consumerSess.createConsumer(new ActiveMQQueue("test")); + TextMessage receivedMessage = (TextMessage)consumer.receive(100); + assertEquals(sentMessage, receivedMessage); + + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthenticationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthenticationTest.java new file mode 100644 index 0000000000..4e77c0125e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthenticationTest.java @@ -0,0 +1,83 @@ +/** + * 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.security; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.AbstractLdapTestUnit; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.apache.directory.server.ldap.LdapServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + + +@RunWith( FrameworkRunner.class ) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP", port=1024)}) +@ApplyLdifFiles( + "org/apache/activemq/security/activemq.ldif" +) +public class LDAPAuthenticationTest extends AbstractLdapTestUnit { + + public BrokerService broker; + + public static LdapServer ldapServer; + + @Before + public void setup() throws Exception { + System.setProperty("ldapPort", String.valueOf(getLdapServer().getPort())); + + broker = BrokerFactory.createBroker("xbean:org/apache/activemq/security/activemq-ldap-auth.xml"); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void shutdown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testWildcard() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn = factory.createQueueConnection("*", "sunflower"); + try { + conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + } catch (Exception e) { + e.printStackTrace(); + return; + } + fail("Should have failed connecting"); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthorizationMap.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthorizationMap.properties new file mode 100644 index 0000000000..fc7b13bc73 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthorizationMap.properties @@ -0,0 +1,33 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +initialContextFactory = com.sun.jndi.ldap.LdapCtxFactory +connectionURL = ldap://localhost:10389 +authentication = simple +connectionUsername = uid=admin,ou=system +connectionPassword = secret +connectionProtocol = s +topicSearchMatching = uid={0},ou=topics,ou=destinations,o=ActiveMQ,dc=example,dc=com +topicSearchSubtree = true +queueSearchMatching = uid={0},ou=queues,ou=destinations,o=ActiveMQ,dc=example,dc=com +queueSearchSubtree = true +adminBase = (cn=admin) +adminAttribute = uniqueMember +readBase = (cn=read) +readAttribute = uniqueMember +writeBAse = (cn=write) +writeAttribute = uniqueMember diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthorizationMapTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthorizationMapTest.java new file mode 100644 index 0000000000..130a0dadb1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPAuthorizationMapTest.java @@ -0,0 +1,156 @@ +/** + * 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.security; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.text.MessageFormat; +import java.util.HashSet; +import java.util.Set; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.directory.DirContext; + +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.jaas.GroupPrincipal; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.AbstractLdapTestUnit; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.apache.directory.server.ldap.LdapServer; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * This test assumes setup like in file 'AMQauth.ldif'. Contents of this file is attached below in comments. + * + * @author ngcutura + * + * + */ +@RunWith(FrameworkRunner.class) +@CreateLdapServer(transports = { @CreateTransport(protocol = "LDAP") }) +@ApplyLdifFiles("org/apache/activemq/security/AMQauth.ldif") +public class LDAPAuthorizationMapTest extends AbstractLdapTestUnit { + private static LDAPAuthorizationMap authMap; + + public static LdapServer ldapServer; + + @Before + public void setup() throws Exception { + authMap = new LDAPAuthorizationMap(); + authMap.setConnectionURL("ldap://localhost:" + getLdapServer().getPort()); + authMap.setTopicSearchMatchingFormat(new MessageFormat("uid={0},ou=topics,ou=destinations,o=ActiveMQ,ou=system")); + authMap.setQueueSearchMatchingFormat(new MessageFormat("uid={0},ou=queues,ou=destinations,o=ActiveMQ,ou=system")); + authMap.setAdvisorySearchBase("uid=ActiveMQ.Advisory,ou=topics,ou=destinations,o=ActiveMQ,ou=system"); + authMap.setTempSearchBase("uid=ActiveMQ.Temp,ou=topics,ou=destinations,o=ActiveMQ,ou=system"); + } + + @Test + public void testOpen() throws Exception { + DirContext ctx = authMap.open(); + HashSet set = new HashSet(); + NamingEnumeration list = ctx.list("ou=destinations,o=ActiveMQ,ou=system"); + while (list.hasMore()) { + NameClassPair ncp = list.next(); + set.add(ncp.getName()); + } + assertTrue(set.contains("ou=topics")); + assertTrue(set.contains("ou=queues")); + } + + /* + * Test method for 'org.apache.activemq.security.LDAPAuthorizationMap.getAdminACLs(ActiveMQDestination)' + */ + @Test + public void testGetAdminACLs() { + ActiveMQDestination q1 = new ActiveMQQueue("queue1"); + Set aclsq1 = authMap.getAdminACLs(q1); + assertEquals(1, aclsq1.size()); + assertTrue(aclsq1.contains(new GroupPrincipal("role1"))); + + ActiveMQDestination t1 = new ActiveMQTopic("topic1"); + Set aclst1 = authMap.getAdminACLs(t1); + assertEquals(1, aclst1.size()); + assertTrue(aclst1.contains(new GroupPrincipal("role1"))); + } + + /* + * Test method for 'org.apache.activemq.security.LDAPAuthorizationMap.getReadACLs(ActiveMQDestination)' + */ + @Test + public void testGetReadACLs() { + ActiveMQDestination q1 = new ActiveMQQueue("queue1"); + Set aclsq1 = authMap.getReadACLs(q1); + assertEquals(1, aclsq1.size()); + assertTrue(aclsq1.contains(new GroupPrincipal("role1"))); + + ActiveMQDestination t1 = new ActiveMQTopic("topic1"); + Set aclst1 = authMap.getReadACLs(t1); + assertEquals(1, aclst1.size()); + assertTrue(aclst1.contains(new GroupPrincipal("role2"))); + } + + /* + * Test method for 'org.apache.activemq.security.LDAPAuthorizationMap.getWriteACLs(ActiveMQDestination)' + */ + @Test + public void testGetWriteACLs() { + ActiveMQDestination q1 = new ActiveMQQueue("queue1"); + Set aclsq1 = authMap.getWriteACLs(q1); + assertEquals(2, aclsq1.size()); + assertTrue(aclsq1.contains(new GroupPrincipal("role1"))); + assertTrue(aclsq1.contains(new GroupPrincipal("role2"))); + + ActiveMQDestination t1 = new ActiveMQTopic("topic1"); + Set aclst1 = authMap.getWriteACLs(t1); + assertEquals(1, aclst1.size()); + assertTrue(aclst1.contains(new GroupPrincipal("role3"))); + } + + @Test + public void testComposite() { + ActiveMQDestination q1 = new ActiveMQQueue("queue1,topic://topic1"); + Set aclsq1 = authMap.getWriteACLs(q1); + assertEquals(0, aclsq1.size()); + } + + @Test + public void testAdvisory() { + ActiveMQDestination dest = AdvisorySupport.getConnectionAdvisoryTopic(); + Set acls = authMap.getWriteACLs(dest); + + assertEquals(1, acls.size()); + assertTrue(acls.contains(new GroupPrincipal("role3"))); + } + + @Test + public void testTemp() { + Set acls = authMap.getTempDestinationAdminACLs(); + + assertEquals(1, acls.size()); + assertTrue(acls.contains(new GroupPrincipal("role1"))); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java new file mode 100644 index 0000000000..63c4cbda88 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/LDAPSecurityTest.java @@ -0,0 +1,152 @@ +/** + * 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.security; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.directory.server.annotations.CreateLdapServer; +import org.apache.directory.server.annotations.CreateTransport; +import org.apache.directory.server.core.annotations.ApplyLdifFiles; +import org.apache.directory.server.core.integ.AbstractLdapTestUnit; +import org.apache.directory.server.core.integ.FrameworkRunner; +import org.apache.directory.server.ldap.LdapServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + + +@RunWith( FrameworkRunner.class ) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP", port=1024)}) +@ApplyLdifFiles( + "org/apache/activemq/security/activemq.ldif" +) +public class LDAPSecurityTest extends AbstractLdapTestUnit { + + public BrokerService broker; + + public static LdapServer ldapServer; + + @Before + public void setup() throws Exception { + System.setProperty("ldapPort", String.valueOf(getLdapServer().getPort())); + + broker = BrokerFactory.createBroker("xbean:org/apache/activemq/security/activemq-ldap.xml"); + broker.start(); + broker.waitUntilStarted(); + } + + @After + public void shutdown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testSendReceive() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Destination queue = sess.createQueue("TEST.FOO"); + + MessageProducer producer = sess.createProducer(queue); + MessageConsumer consumer = sess.createConsumer(queue); + + producer.send(sess.createTextMessage("test")); + Message msg = consumer.receive(1000); + assertNotNull(msg); + } + + @Test + public void testSendTopic() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Destination topic = sess.createTopic("TEST.BAR"); + + MessageProducer producer = sess.createProducer(topic); + MessageConsumer consumer = sess.createConsumer(topic); + + producer.send(sess.createTextMessage("test")); + Message msg = consumer.receive(1000); + assertNotNull(msg); + } + + @Test + public void testSendDenied() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createQueue("ADMIN.FOO"); + + try { + MessageProducer producer = sess.createProducer(queue); + producer.send(sess.createTextMessage("test")); + fail("expect auth exception"); + } catch (JMSException expected) { + } + } + + @Test + public void testCompositeSendDenied() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createQueue("TEST.FOO,ADMIN.FOO"); + + try { + MessageProducer producer = sess.createProducer(queue); + producer.send(sess.createTextMessage("test")); + fail("expect auth exception"); + } catch (JMSException expected) { + } + } + + @Test + public void testTempDestinations() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn = factory.createQueueConnection("jdoe", "sunflower"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createTemporaryQueue(); + + MessageProducer producer = sess.createProducer(queue); + MessageConsumer consumer = sess.createConsumer(queue); + + producer.send(sess.createTextMessage("test")); + Message msg = consumer.receive(1000); + assertNotNull(msg); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SecurityJMXTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SecurityJMXTest.java new file mode 100644 index 0000000000..b62fccb90d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SecurityJMXTest.java @@ -0,0 +1,108 @@ +/** + * 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.security; + + +import java.net.URI; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +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.broker.jmx.QueueViewMBean; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SecurityJMXTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleAuthenticationPluginTest.class); + private BrokerService broker; + + @Override + public void setUp() throws Exception { + broker = createBroker(); + broker.waitUntilStarted(); + } + + @Override + public void tearDown() throws Exception { + broker.stop(); + } + + public void testMoveMessages() throws Exception { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1199/jmxrmi"); + JMXConnector connector = JMXConnectorFactory.connect(url, null); + connector.connect(); + MBeanServerConnection connection = connector.getMBeanServerConnection(); + ObjectName name = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost," + + "destinationType=Queue,destinationName=TEST.Q"); + QueueViewMBean queueMbean = MBeanServerInvocationHandler.newProxyInstance(connection, name, QueueViewMBean.class, true); + String msgId = queueMbean.sendTextMessage("test", "system", "manager"); + queueMbean.moveMessageTo(msgId, "TEST1.Q"); + } + + public void testBrowseExpiredMessages() throws Exception { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1199/jmxrmi"); + JMXConnector connector = JMXConnectorFactory.connect(url, null); + connector.connect(); + MBeanServerConnection connection = connector.getMBeanServerConnection(); + ObjectName name = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost," + + "destinationType=Queue,destinationName=TEST.Q"); + QueueViewMBean queueMbean = MBeanServerInvocationHandler.newProxyInstance(connection, name, QueueViewMBean.class, true); + HashMap headers = new HashMap(); + headers.put("timeToLive", Long.toString(2000)); + headers.put("JMSDeliveryMode", Integer.toString(DeliveryMode.PERSISTENT)); + queueMbean.sendTextMessage(headers, "test", "system", "manager"); + // allow message to expire on the queue + TimeUnit.SECONDS.sleep(4); + + Connection c = new ActiveMQConnectionFactory("vm://localhost").createConnection("system", "manager"); + c.start(); + + // browser consumer will force expriation check on addConsumer + QueueBrowser browser = c.createSession(false, Session.AUTO_ACKNOWLEDGE).createBrowser(new ActiveMQQueue("TEST.Q")); + assertTrue("no message in the q", !browser.getEnumeration().hasMoreElements()); + + // verify dlq got the message, no security exception as brokers context is now used + browser = c.createSession(false, Session.AUTO_ACKNOWLEDGE).createBrowser(new ActiveMQQueue("ActiveMQ.DLQ")); + assertTrue("one message in the dlq", browser.getEnumeration().hasMoreElements()); + } + + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/simple-auth-broker.xml"); + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SecurityTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SecurityTestSupport.java new file mode 100644 index 0000000000..a40970ccb0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SecurityTestSupport.java @@ -0,0 +1,263 @@ +/** + * 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.security; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +/** + * + */ +public class SecurityTestSupport extends JmsTestSupport { + + public ActiveMQDestination destination; + + /** + * Overrides to set the JMSXUserID flag to true. + */ + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.setPopulateJMSXUserID(true); + return broker; + } + + public void testUserReceiveFails() throws JMSException { + doReceive(true); + } + + public void testInvalidAuthentication() throws JMSException { + try { + // No user id + Connection c = factory.createConnection(); + connections.add(c); + c.start(); + fail("Expected exception."); + } catch (JMSException e) { + } + + try { + // Bad password + Connection c = factory.createConnection("user", "krap"); + connections.add(c); + c.start(); + fail("Expected exception."); + } catch (JMSException e) { + } + + try { + // Bad userid + Connection c = factory.createConnection("userkrap", null); + connections.add(c); + c.start(); + fail("Expected exception."); + } catch (JMSException e) { + } + } + + public void testUserReceiveSucceeds() throws JMSException { + Message m = doReceive(false); + assertEquals("system", ((ActiveMQMessage)m).getUserID()); + assertEquals("system", m.getStringProperty("JMSXUserID")); + } + + public void testGuestReceiveSucceeds() throws JMSException { + doReceive(false); + } + + public void testGuestReceiveFails() throws JMSException { + doReceive(true); + } + + public void testUserSendSucceeds() throws JMSException { + Message m = doSend(false); + assertEquals("user", ((ActiveMQMessage)m).getUserID()); + assertEquals("user", m.getStringProperty("JMSXUserID")); + } + + public void testUserSendFails() throws JMSException { + doSend(true); + } + + public void testGuestSendFails() throws JMSException { + doSend(true); + } + + public void testGuestSendSucceeds() throws JMSException { + doSend(false); + } + + /** + * @throws JMSException + */ + public Message doSend(boolean fail) throws JMSException { + + Connection adminConnection = factory.createConnection("system", "manager"); + connections.add(adminConnection); + + adminConnection.start(); + Session adminSession = adminConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = adminSession.createConsumer(destination); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + try { + sendMessages(session, destination, 1); + } catch (JMSException e) { + // If test is expected to fail, the cause must only be a + // SecurityException + // otherwise rethrow the exception + if (!fail || !(e.getCause() instanceof SecurityException)) { + throw e; + } + } + + Message m = consumer.receive(1000); + if (fail) { + assertNull(m); + } else { + assertNotNull(m); + assertEquals("0", ((TextMessage)m).getText()); + assertNull(consumer.receiveNoWait()); + } + return m; + } + + /** + * @throws JMSException + */ + public Message doReceive(boolean fail) throws JMSException { + + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = null; + try { + consumer = session.createConsumer(destination); + if (fail) { + fail("Expected failure due to security constraint."); + } + } catch (JMSException e) { + if (fail && e.getCause() instanceof SecurityException) { + return null; + } + throw e; + } + + Connection adminConnection = factory.createConnection("system", "manager"); + connections.add(adminConnection); + Session adminSession = adminConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + sendMessages(adminSession, destination, 1); + + Message m = consumer.receive(1000); + assertNotNull(m); + assertEquals("0", ((TextMessage)m).getText()); + assertNull(consumer.receiveNoWait()); + return m; + + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserReceiveFails() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("USERS.BY_PASS, TEST"), new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestInvalidAuthentication() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserReceiveSucceeds() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestGuestReceiveSucceeds() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestGuestReceiveFails() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUESTS.BY_PASS,TEST"), new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO") }); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserSendSucceeds() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("USERS.FOO"), new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("USERS.FOO"), + new ActiveMQTopic("GUEST.BAR")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserSendFails() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("USERS.BY_PASS,TEST"), new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestGuestSendFails() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUESTS.BY_PASS,TEST"), new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestGuestSendSucceeds() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR")}); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAnonymousPluginTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAnonymousPluginTest.java new file mode 100644 index 0000000000..c97515e999 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAnonymousPluginTest.java @@ -0,0 +1,117 @@ +/** + * 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.security; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import junit.framework.Test; + +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +public class SimpleAnonymousPluginTest extends SimpleAuthenticationPluginTest { + + public static Test suite() { + return suite(SimpleAnonymousPluginTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/simple-anonymous-broker.xml"); + } + + @Override + public void testInvalidAuthentication() throws JMSException { + + try { + // Bad password + Connection c = factory.createConnection("user", "krap"); + connections.add(c); + c.start(); + fail("Expected exception."); + } catch (JMSException e) { + } + + try { + // Bad userid + Connection c = factory.createConnection("userkrap", null); + connections.add(c); + c.start(); + fail("Expected exception."); + } catch (JMSException e) { + } + } + + public void testAnonymousReceiveSucceeds() throws JMSException { + doReceive(false); + } + + public void testAnonymousReceiveFails() throws JMSException { + doReceive(true); + } + + public void testAnonymousSendFails() throws JMSException { + doSend(true); + } + + public void testAnonymousSendSucceeds() throws JMSException { + doSend(false); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestAnonymousReceiveSucceeds() { + addCombinationValues("userName", new Object[] { null }); + addCombinationValues("password", new Object[] { null }); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestAnonymousReceiveFails() { + addCombinationValues("userName", new Object[] { null }); + addCombinationValues("password", new Object[] { null }); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO") }); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestAnonymousSendFails() { + addCombinationValues("userName", new Object[] { null }); + addCombinationValues("password", new Object[] { null }); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestAnonymousSendSucceeds() { + addCombinationValues("userName", new Object[] { null }); + addCombinationValues("password", new Object[] { null }); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR")}); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthenticationPluginSeparatorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthenticationPluginSeparatorTest.java new file mode 100644 index 0000000000..0456841f73 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthenticationPluginSeparatorTest.java @@ -0,0 +1,120 @@ +/** + * 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.security; + +import junit.framework.Test; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +public class SimpleAuthenticationPluginSeparatorTest extends SimpleAuthenticationPluginTest { + + public static Test suite() { + return suite(SimpleAuthenticationPluginSeparatorTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/simple-auth-separator.xml"); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserReceiveFails() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("GUEST/BAR"), new ActiveMQTopic("GUEST/BAR")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestInvalidAuthentication() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserReceiveSucceeds() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("USERS/FOO"), new ActiveMQTopic("USERS/FOO")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestGuestReceiveSucceeds() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST/BAR"), new ActiveMQTopic("GUEST/BAR")}); + } + + /** + * @see {@link org.apache.activemq.CombinationTestSupport} + */ + public void initCombosForTestGuestReceiveFails() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS/FOO"), new ActiveMQTopic("USERS/FOO") }); + } + + /** + * @see {@link org.apache.activemq.CombinationTestSupport} + */ + public void initCombosForTestUserSendSucceeds() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("USERS/FOO"), new ActiveMQQueue("GUEST/BAR"), new ActiveMQTopic("USERS/FOO"), + new ActiveMQTopic("GUEST/BAR")}); + } + + /** + * @see {@link org.apache.activemq.CombinationTestSupport} + */ + public void initCombosForTestUserSendFails() { + addCombinationValues("userName", new Object[] {"user"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST")}); + } + + /** + * @see {@link org.apache.activemq.CombinationTestSupport} + */ + public void initCombosForTestGuestSendFails() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS/FOO"), new ActiveMQTopic("USERS/FOO")}); + } + + /** + * @see {@link org.apache.activemq.CombinationTestSupport} + */ + public void initCombosForTestGuestSendSucceeds() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST/BAR"), new ActiveMQTopic("GUEST/BAR")}); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthenticationPluginTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthenticationPluginTest.java new file mode 100644 index 0000000000..1a154b261b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthenticationPluginTest.java @@ -0,0 +1,149 @@ +/** + * 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.security; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.JMSSecurityException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryTopic; +import javax.management.ObjectName; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnection; +import org.apache.activemq.broker.TransportConnectionState; +import org.apache.activemq.broker.jmx.TopicViewMBean; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SimpleAuthenticationPluginTest extends SecurityTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleAuthenticationPluginTest.class); + + public static Test suite() { + return suite(SimpleAuthenticationPluginTest.class); + } + + @Override + protected void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/simple-auth-broker.xml"); + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestPredefinedDestinations() { + addCombinationValues("userName", new Object[] {"guest"}); + addCombinationValues("password", new Object[] {"password"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST.Q")}); + } + + public void testPredefinedDestinations() throws JMSException { + Message sent = doSend(false); + assertEquals("guest", ((ActiveMQMessage)sent).getUserID()); + assertEquals("guest", sent.getStringProperty("JMSXUserID")); + } + + public void testTempDestinations() throws Exception { + Connection conn = factory.createConnection("guest", "password"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + String name = "org.apache.activemq:BrokerName=localhost,Type=TempTopic"; + try { + conn.start(); + TemporaryTopic temp = sess.createTemporaryTopic(); + name += ",Destination=" + temp.getTopicName().replaceAll(":", "_"); + fail("Should have failed creating a temp topic"); + } catch (Exception ignore) {} + + ObjectName objName = new ObjectName(name); + TopicViewMBean mbean = (TopicViewMBean)broker.getManagementContext().newProxyInstance(objName, TopicViewMBean.class, true); + try { + System.out.println(mbean.getName()); + fail("Shouldn't have created a temp topic"); + } catch (Exception ignore) {} + } + + public void testConnectionStartThrowsJMSSecurityException() throws Exception { + + Connection connection = factory.createConnection("badUser", "password"); + try { + connection.start(); + fail("Should throw JMSSecurityException"); + } catch (JMSSecurityException jmsEx) { + } catch (Exception e) { + LOG.info("Expected JMSSecurityException but was: {}", e.getClass()); + fail("Should throw JMSSecurityException"); + } + } + + public void testSecurityContextClearedOnPurge() throws Exception { + + connection.close(); + ActiveMQConnectionFactory tcpFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString()); + ActiveMQConnection conn = (ActiveMQConnection) tcpFactory.createConnection("user", "password"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + + final int numDests = broker.getRegionBroker().getDestinations().length; + for (int i=0; i<10; i++) { + MessageProducer p = sess.createProducer(new ActiveMQQueue("USERS.PURGE." + i)); + p.close(); + } + + assertTrue("dests are purged", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("dests, orig: " + numDests + ", now: "+ broker.getRegionBroker().getDestinations().length); + return (numDests + 1) == broker.getRegionBroker().getDestinations().length; + } + })); + + // verify removed from connection security context + TransportConnection brokerConnection = broker.getTransportConnectors().get(0).getConnections().get(0); + TransportConnectionState transportConnectionState = brokerConnection.lookupConnectionState(conn.getConnectionInfo().getConnectionId()); + assertEquals("no destinations", 0, transportConnectionState.getContext().getSecurityContext().getAuthorizedWriteDests().size()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthorizationMapTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthorizationMapTest.java new file mode 100644 index 0000000000..f86e0fc399 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleAuthorizationMapTest.java @@ -0,0 +1,28 @@ +/** + * 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.security; + +/** + * + * + */ +public class SimpleAuthorizationMapTest extends AuthorizationMapTest { + + protected AuthorizationMap createAuthorizationMap() { + return SimpleSecurityBrokerSystemTest.createAuthorizationMap(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleSecurityBrokerSystemTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleSecurityBrokerSystemTest.java new file mode 100644 index 0000000000..d5f8b80ccb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/SimpleSecurityBrokerSystemTest.java @@ -0,0 +1,187 @@ +/** + * 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.security; + +import java.lang.management.ManagementFactory; +import java.net.URL; +import java.security.Principal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import junit.framework.Test; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.filter.DestinationMap; +import org.apache.activemq.jaas.GroupPrincipal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; + +/** + * Tests that the broker allows/fails access to destinations based on the + * security policy installed on the broker. + * + * + */ +public class SimpleSecurityBrokerSystemTest extends SecurityTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(SimpleSecurityBrokerSystemTest.class); + + public static final GroupPrincipal GUESTS = new GroupPrincipal("guests"); + public static final GroupPrincipal USERS = new GroupPrincipal("users"); + public static final GroupPrincipal ADMINS = new GroupPrincipal("admins"); + public static Principal WILDCARD; + static { + try { + WILDCARD = (Principal) DefaultAuthorizationMap.createGroupPrincipal("*", GroupPrincipal.class.getName()); + } catch (Exception e) { + LOG.error("Failed to make wildcard principal", e); + } + } + + public BrokerPlugin authorizationPlugin; + public BrokerPlugin authenticationPlugin; + + static { + String path = System.getProperty("java.security.auth.login.config"); + if (path == null) { + URL resource = SimpleSecurityBrokerSystemTest.class.getClassLoader().getResource("login.config"); + if (resource != null) { + path = resource.getFile(); + System.setProperty("java.security.auth.login.config", path); + } + } + LOG.info("Path to login config: " + path); + } + + public static Test suite() { + return suite(SimpleSecurityBrokerSystemTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + /** + * @throws javax.jms.JMSException + */ + public void testPopulateJMSXUserID() throws Exception { + destination = new ActiveMQQueue("TEST"); + Connection connection = factory.createConnection("system", "manager"); + connections.add(connection); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + sendMessages(session, destination, 1); + + // make sure that the JMSXUserID is exposed over JMX + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + CompositeData[] browse = (CompositeData[]) mbs.invoke(new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=TEST"), "browse", null, null); + assertEquals("system", browse[0].get("JMSXUserID")); + + // And also via JMS. + MessageConsumer consumer = session.createConsumer(destination); + Message m = consumer.receive(1000); + assertTrue(m.propertyExists("JMSXUserID")); + assertEquals("system", m.getStringProperty("JMSXUserID")); + } + + public static AuthorizationMap createAuthorizationMap() { + DestinationMap readAccess = new DefaultAuthorizationMap(); + readAccess.put(new ActiveMQQueue(">"), ADMINS); + readAccess.put(new ActiveMQQueue("USERS.>"), USERS); + readAccess.put(new ActiveMQQueue("GUEST.>"), GUESTS); + readAccess.put(new ActiveMQTopic(">"), ADMINS); + readAccess.put(new ActiveMQTopic("USERS.>"), USERS); + readAccess.put(new ActiveMQTopic("GUEST.>"), GUESTS); + + DestinationMap writeAccess = new DefaultAuthorizationMap(); + writeAccess.put(new ActiveMQQueue(">"), ADMINS); + writeAccess.put(new ActiveMQQueue("USERS.>"), USERS); + writeAccess.put(new ActiveMQQueue("GUEST.>"), USERS); + writeAccess.put(new ActiveMQQueue("GUEST.>"), GUESTS); + writeAccess.put(new ActiveMQTopic(">"), ADMINS); + writeAccess.put(new ActiveMQTopic("USERS.>"), USERS); + writeAccess.put(new ActiveMQTopic("GUEST.>"), USERS); + writeAccess.put(new ActiveMQTopic("GUEST.>"), GUESTS); + + readAccess.put(new ActiveMQTopic("ActiveMQ.Advisory.>"), WILDCARD); + writeAccess.put(new ActiveMQTopic("ActiveMQ.Advisory.>"), WILDCARD); + + DestinationMap adminAccess = new DefaultAuthorizationMap(); + adminAccess.put(new ActiveMQTopic(">"), ADMINS); + adminAccess.put(new ActiveMQTopic(">"), USERS); + adminAccess.put(new ActiveMQTopic(">"), GUESTS); + adminAccess.put(new ActiveMQQueue(">"), ADMINS); + adminAccess.put(new ActiveMQQueue(">"), USERS); + adminAccess.put(new ActiveMQQueue(">"), GUESTS); + + return new SimpleAuthorizationMap(writeAccess, readAccess, adminAccess); + } + + public static class SimpleAuthenticationFactory implements BrokerPlugin { + public Broker installPlugin(Broker broker) { + + HashMap u = new HashMap(); + u.put("system", "manager"); + u.put("user", "password"); + u.put("guest", "password"); + + Map> groups = new HashMap>(); + groups.put("system", new HashSet(Arrays.asList(new Principal[] {ADMINS, USERS}))); + groups.put("user", new HashSet(Arrays.asList(new Principal[] {USERS}))); + groups.put("guest", new HashSet(Arrays.asList(new Principal[] {GUESTS}))); + + return new SimpleAuthenticationBroker(broker, u, groups); + } + + public String toString() { + return "SimpleAuthenticationBroker"; + } + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombos() { + addCombinationValues("authorizationPlugin", + new Object[] {new AuthorizationPlugin(createAuthorizationMap())}); + addCombinationValues("authenticationPlugin", new Object[] {new SimpleAuthenticationFactory(), + new JaasAuthenticationPlugin()}); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.setPopulateJMSXUserID(true); + broker.setUseAuthenticatedPrincipalForJMSXUserID(true); + broker.setPlugins(new BrokerPlugin[] {authorizationPlugin, authenticationPlugin}); + broker.setPersistent(false); + return broker; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubDoNothingCallbackHandler.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubDoNothingCallbackHandler.java new file mode 100644 index 0000000000..aa9056c2dc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubDoNothingCallbackHandler.java @@ -0,0 +1,31 @@ +/** + * 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.security; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +public class StubDoNothingCallbackHandler implements CallbackHandler { + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java new file mode 100644 index 0000000000..7cb9282982 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java @@ -0,0 +1,43 @@ +/** + * 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.security; + +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +public class StubDualJaasConfiguration extends Configuration { + private AppConfigurationEntry nonSslConfigEntry; + private AppConfigurationEntry sslConfigEntry; + + public StubDualJaasConfiguration(AppConfigurationEntry nonSslConfigEntry, AppConfigurationEntry sslConfigEntry) { + this.nonSslConfigEntry = nonSslConfigEntry; + this.sslConfigEntry = sslConfigEntry; + } + + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + if ("activemq-domain".equals(name)) { + return new AppConfigurationEntry[] {nonSslConfigEntry}; + } else { + return new AppConfigurationEntry[] {sslConfigEntry}; + } + } + + public void refresh() { + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubJaasConfiguration.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubJaasConfiguration.java new file mode 100644 index 0000000000..9f66d303b5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubJaasConfiguration.java @@ -0,0 +1,37 @@ +/** + * 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.security; + +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +public class StubJaasConfiguration extends Configuration { + private AppConfigurationEntry configEntry; + + public StubJaasConfiguration(AppConfigurationEntry configEntry) { + this.configEntry = configEntry; + } + + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + return new AppConfigurationEntry[] {configEntry}; + } + + public void refresh() { + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubLoginModule.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubLoginModule.java new file mode 100644 index 0000000000..5492831176 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubLoginModule.java @@ -0,0 +1,98 @@ +/** + * 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.security; + +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.apache.activemq.jaas.GroupPrincipal; +import org.apache.activemq.jaas.UserPrincipal; + +public class StubLoginModule implements LoginModule { + public static final String ALLOW_LOGIN_PROPERTY = "org.apache.activemq.jaas.stubproperties.allow_login"; + public static final String USERS_PROPERTY = "org.apache.activemq.jaas.stubproperties.users"; + public static final String GROUPS_PROPERTY = "org.apache.activemq.jaas.stubproperties.groups"; + + private Subject subject; + + private String userNames[]; + private String groupNames[]; + private boolean allowLogin; + + @Override + @SuppressWarnings("rawtypes") + public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { + String allowLoginString = (String)(options.get(ALLOW_LOGIN_PROPERTY)); + String usersString = (String)(options.get(USERS_PROPERTY)); + String groupsString = (String)(options.get(GROUPS_PROPERTY)); + + this.subject = subject; + + allowLogin = Boolean.parseBoolean(allowLoginString); + userNames = usersString.split(","); + groupNames = groupsString.split(","); + } + + @Override + public boolean login() throws LoginException { + if (!allowLogin) { + throw new FailedLoginException("Login was not allowed (as specified in configuration)."); + } + + return true; + } + + @Override + public boolean commit() throws LoginException { + if (!allowLogin) { + throw new FailedLoginException("Login was not allowed (as specified in configuration)."); + } + + for (int i = 0; i < userNames.length; ++i) { + if (userNames[i].length() > 0) { + subject.getPrincipals().add(new UserPrincipal(userNames[i])); + } + } + + for (int i = 0; i < groupNames.length; ++i) { + if (groupNames[i].length() > 0) { + subject.getPrincipals().add(new GroupPrincipal(groupNames[i])); + } + } + + return true; + } + + @Override + public boolean abort() throws LoginException { + return true; + } + + @Override + public boolean logout() throws LoginException { + subject.getPrincipals().clear(); + + return true; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubSecurityContext.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubSecurityContext.java new file mode 100644 index 0000000000..7ac2d3b4c2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/StubSecurityContext.java @@ -0,0 +1,31 @@ +/** + * 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.security; + +import java.security.Principal; +import java.util.Set; + +public class StubSecurityContext extends SecurityContext { + StubSecurityContext() { + super(""); + } + + public Set getPrincipals() { + return null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityTest.java new file mode 100644 index 0000000000..d01e6078c2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityTest.java @@ -0,0 +1,53 @@ +/** + * 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.security; + +import java.net.URI; + +import junit.framework.Test; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class XBeanSecurityTest extends SecurityTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(XBeanSecurityTest.class); + + public static Test suite() { + return suite(XBeanSecurityTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/jaas-broker.xml"); + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestNoCredentialsOnlyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestNoCredentialsOnlyTest.java new file mode 100644 index 0000000000..14b6dccccf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestNoCredentialsOnlyTest.java @@ -0,0 +1,139 @@ +/** + * 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.security; + +import java.net.URI; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class XBeanSecurityWithGuestNoCredentialsOnlyTest extends JmsTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(XBeanSecurityWithGuestNoCredentialsOnlyTest.class); + public ActiveMQDestination destination; + + public static Test suite() { + return suite(XBeanSecurityWithGuestNoCredentialsOnlyTest.class); + } + + public void testUserSendGoodPassword() throws JMSException { + Message m = doSend(false); + assertEquals("system", ((ActiveMQMessage)m).getUserID()); + assertEquals("system", m.getStringProperty("JMSXUserID")); + } + + public void testUserSendWrongPassword() throws JMSException { + try { + doSend(true); + fail("expect exception on connect"); + } catch (JMSException expected) { + assertTrue("cause as expected", expected.getCause() instanceof SecurityException); + } + } + + public void testUserSendNoCredentials() throws JMSException { + Message m = doSend(false); + // note brokerService.useAuthenticatedPrincipalForJMXUserID=true for this + assertEquals("guest", ((ActiveMQMessage)m).getUserID()); + assertEquals("guest", m.getStringProperty("JMSXUserID")); + } + + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/jaas-broker-guest-no-creds-only.xml"); + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + + public Message doSend(boolean fail) throws JMSException { + + Connection adminConnection = factory.createConnection("system", "manager"); + connections.add(adminConnection); + + adminConnection.start(); + Session adminSession = adminConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = adminSession.createConsumer(destination); + + connections.remove(connection); + connection = (ActiveMQConnection)factory.createConnection(userName, password); + connections.add(connection); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + try { + sendMessages(session, destination, 1); + } catch (JMSException e) { + // If test is expected to fail, the cause must only be a + // SecurityException + // otherwise rethrow the exception + if (!fail || !(e.getCause() instanceof SecurityException)) { + throw e; + } + } + + Message m = consumer.receive(1000); + if (fail) { + assertNull(m); + } else { + assertNotNull(m); + assertEquals("0", ((TextMessage)m).getText()); + assertNull(consumer.receiveNoWait()); + } + return m; + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserSendGoodPassword() { + addCombinationValues("userName", new Object[] {"system"}); + addCombinationValues("password", new Object[] {"manager"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("test"), new ActiveMQTopic("test")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserSendWrongPassword() { + addCombinationValues("userName", new Object[] {"system"}); + addCombinationValues("password", new Object[] {"wrongpassword"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GuestQueue")}); + } + + public void initCombosForTestUserSendNoCredentials() { + addCombinationValues("userName", new Object[] {null, "system"}); + addCombinationValues("password", new Object[] {null}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GuestQueue")}); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestTest.java new file mode 100644 index 0000000000..16f95b49a8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestTest.java @@ -0,0 +1,137 @@ +/** + * 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.security; + +import java.net.URI; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class XBeanSecurityWithGuestTest extends JmsTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(XBeanSecurityWithGuestTest.class); + public ActiveMQDestination destination; + + public static Test suite() { + return suite(XBeanSecurityWithGuestTest.class); + } + + public void testUserSendGoodPassword() throws JMSException { + Message m = doSend(false); + assertEquals("system", ((ActiveMQMessage)m).getUserID()); + assertEquals("system", m.getStringProperty("JMSXUserID")); + } + + public void testUserSendWrongPassword() throws JMSException { + Message m = doSend(false); + // note brokerService.useAuthenticatedPrincipalForJMXUserID=true for this + assertEquals("guest", ((ActiveMQMessage)m).getUserID()); + assertEquals("guest", m.getStringProperty("JMSXUserID")); + } + + public void testUserSendNoCredentials() throws JMSException { + Message m = doSend(false); + // note brokerService.useAuthenticatedPrincipalForJMXUserID=true for this + assertEquals("guest", ((ActiveMQMessage)m).getUserID()); + assertEquals("guest", m.getStringProperty("JMSXUserID")); + } + + protected BrokerService createBroker() throws Exception { + return createBroker("org/apache/activemq/security/jaas-broker-guest.xml"); + } + + protected BrokerService createBroker(String uri) throws Exception { + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + + public Message doSend(boolean fail) throws JMSException { + + Connection adminConnection = factory.createConnection("system", "manager"); + connections.add(adminConnection); + + adminConnection.start(); + Session adminSession = adminConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = adminSession.createConsumer(destination); + + connections.remove(connection); + connection = (ActiveMQConnection)factory.createConnection(userName, password); + connections.add(connection); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + try { + sendMessages(session, destination, 1); + } catch (JMSException e) { + // If test is expected to fail, the cause must only be a + // SecurityException + // otherwise rethrow the exception + if (!fail || !(e.getCause() instanceof SecurityException)) { + throw e; + } + } + + Message m = consumer.receive(1000); + if (fail) { + assertNull(m); + } else { + assertNotNull(m); + assertEquals("0", ((TextMessage)m).getText()); + assertNull(consumer.receiveNoWait()); + } + return m; + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserSendGoodPassword() { + addCombinationValues("userName", new Object[] {"system"}); + addCombinationValues("password", new Object[] {"manager"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("test"), new ActiveMQTopic("test")}); + } + + /** + * @see {@link CombinationTestSupport} + */ + public void initCombosForTestUserSendWrongPassword() { + addCombinationValues("userName", new Object[] {"system"}); + addCombinationValues("password", new Object[] {"wrongpassword"}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GuestQueue")}); + } + + public void initCombosForTestUserSendNoCredentials() { + addCombinationValues("userName", new Object[] {"", null}); + addCombinationValues("password", new Object[] {"", null}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("GuestQueue")}); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSslContextTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSslContextTest.java new file mode 100644 index 0000000000..da8b6ca8f9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/XBeanSslContextTest.java @@ -0,0 +1,41 @@ +/** + * 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.security; + +import java.net.URI; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Test; + +public class XBeanSslContextTest { + + BrokerService broker; + + @Test + public void testSslContextElement() throws Exception { + broker = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/security/activemq-sslcontext.xml")); + } + + @After + public void stopBroker() throws Exception { + if (broker != null) + broker.stop(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-add.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-add.ldif new file mode 100644 index 0000000000..e9235f3848 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-add.ldif @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +## FAILED + +dn: cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: FAILED +description: New queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-delete.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-delete.ldif new file mode 100644 index 0000000000..45e4f887e9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-delete.ldif @@ -0,0 +1,40 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy-add.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy-add.ldif new file mode 100644 index 0000000000..48f8b6a7f6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy-add.ldif @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +## FAILED + +dn: cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: FAILED +description: New queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy-delete.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy-delete.ldif new file mode 100644 index 0000000000..9cc98920a8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy-delete.ldif @@ -0,0 +1,38 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +changetype: delete + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy.ldif new file mode 100644 index 0000000000..3ad7459afe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy.ldif @@ -0,0 +1,264 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +########################## +## Define basic objects ## +########################## + +dn: ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: ActiveMQ + +dn: ou=Services,ou=system +ou: Services +objectClass: organizationalUnit +objectClass: top + +dn: cn=mqbroker,ou=Services,ou=system +cn: mqbroker +objectClass: organizationalRole +objectClass: top +objectClass: simpleSecurityObject +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +description: Bind user for MQ broker + + +################### +## Define groups ## +################### + + +dn: ou=Group,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Group + +dn: cn=admins,ou=Group,ou=ActiveMQ,ou=system +cn: admins +member: uid=admin +objectClass: groupOfNames +objectClass: top + +dn: cn=users,ou=Group,ou=ActiveMQ,ou=system +cn: users +member: uid=jdoe +objectClass: groupOfNames +objectClass: top + + +################## +## Define users ## +################## + + +dn: ou=User,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: User + +dn: uid=admin,ou=User,ou=ActiveMQ,ou=system +uid: admin +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectClass: account +objectClass: simpleSecurityObject +objectClass: top + + +dn: uid=jdoe,ou=User,ou=ActiveMQ,ou=system +uid: jdoe +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectclass: inetOrgPerson +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Jane Doe +sn: Doe + + +######################### +## Define destinations ## +######################### + +dn: ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Destination + +dn: ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Topic + +dn: ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Queue + +## TEST.FOO + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: TEST.FOO +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + + +## FOO.> + +dn: cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: FOO.$ +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + + +## BAR.* + +dn: cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: BAR.* +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + +####################### +## Define advisories ## +####################### + +dn: cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: ActiveMQ.Advisory.$ +objectClass: applicationProcess +objectClass: top +description: Advisory topics + +dn: cn=read,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: write +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +###################### +## Define temporary ## +###################### + +dn: ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Temp + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +cn: write +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy.xml new file mode 100644 index 0000000000..911acba553 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds-legacy.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds.ldif new file mode 100644 index 0000000000..afe6816c88 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds.ldif @@ -0,0 +1,294 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +########################## +## Define basic objects ## +########################## + +dn: ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: ActiveMQ + +dn: ou=Services,ou=system +ou: Services +objectClass: organizationalUnit +objectClass: top + +dn: cn=mqbroker,ou=Services,ou=system +cn: mqbroker +objectClass: organizationalRole +objectClass: top +objectClass: simpleSecurityObject +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +description: Bind user for MQ broker + + +################### +## Define groups ## +################### + + +dn: ou=Group,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Group + +dn: cn=admins,ou=Group,ou=ActiveMQ,ou=system +cn: admins +member: uid=admin,ou=User,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=users,ou=Group,ou=ActiveMQ,ou=system +cn: users +member: uid=jdoe,ou=User,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + + +################## +## Define users ## +################## + + +dn: ou=User,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: User + +dn: uid=admin,ou=User,ou=ActiveMQ,ou=system +uid: admin +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectClass: account +objectClass: simpleSecurityObject +objectClass: top + + +dn: uid=jdoe,ou=User,ou=ActiveMQ,ou=system +uid: jdoe +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectclass: inetOrgPerson +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Jane Doe +sn: Doe + + +######################### +## Define destinations ## +######################### + +dn: ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Destination + +dn: ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Topic + +dn: ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Queue + +## TEST.FOO + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: TEST.FOO +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system + +## TEST.FOOBAR + +dn: cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: TEST.BAR +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: uid=jdoe,ou=User,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: uid=jdoe,ou=User,ou=ActiveMQ,ou=system + +## FOO.> + +dn: cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: FOO.$ +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system + +## BAR.* + +dn: cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: BAR.* +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system + +####################### +## Define advisories ## +####################### + +dn: cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: ActiveMQ.Advisory.$ +objectClass: applicationProcess +objectClass: top +description: Advisory topics + +dn: cn=read,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: write +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +###################### +## Define temporary ## +###################### + +dn: ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Temp + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +cn: write +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +member: cn=admins,ou=Group,ou=ActiveMQ,ou=system +member: cn=users,ou=Group,ou=ActiveMQ,ou=system +objectClass: groupOfNames +objectClass: top diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds.xml new file mode 100644 index 0000000000..67768c1491 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-apacheds.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-ldap-auth.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-ldap-auth.xml new file mode 100644 index 0000000000..8a11a6a483 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-ldap-auth.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-ldap.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-ldap.xml new file mode 100644 index 0000000000..3ab048cabf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-ldap.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-add.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-add.ldif new file mode 100644 index 0000000000..34beb9f348 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-add.ldif @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +## FAILED + +dn: cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: FAILED +description: New queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-delete.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-delete.ldif new file mode 100644 index 0000000000..f7767811dc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-delete.ldif @@ -0,0 +1,38 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy-add.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy-add.ldif new file mode 100644 index 0000000000..1c146de509 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy-add.ldif @@ -0,0 +1,47 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +## FAILED + +dn: cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: FAILED +description: New queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FAILED,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy-delete.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy-delete.ldif new file mode 100644 index 0000000000..f7767811dc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy-delete.ldif @@ -0,0 +1,38 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +changetype: delete + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy.ldif new file mode 100644 index 0000000000..f9d2a2f47b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap-legacy.ldif @@ -0,0 +1,281 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +########################## +## Define basic objects ## +########################## + +dn: dc=apache,dc=org +objectClass: dcObject +objectClass: organization +dc: apache +o: Apache + +dn: dc=activemq,dc=apache,dc=org +objectClass: dcObject +objectClass: container +objectClass: top +cn: activemq +dc: activemq + +dn: ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: ActiveMQ + +dn: ou=Services,dc=activemq,dc=apache,dc=org +ou: Services +objectClass: organizationalUnit +objectClass: top + +dn: cn=mqbroker,ou=Services,dc=activemq,dc=apache,dc=org +cn: mqbroker +objectClass: organizationalRole +objectClass: top +objectClass: simpleSecurityObject +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +description: Bind user for MQ broker + + +################### +## Define groups ## +################### + + +dn: ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Group + +dn: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admins +member: uid=admin +objectClass: groupOfNames +objectClass: top + +dn: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: users +member: uid=jdoe +objectClass: groupOfNames +objectClass: top + + +################## +## Define users ## +################## + + +dn: ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: User + +dn: uid=admin,ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +uid: admin +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectclass: uidObject +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Admin +sn: Admin + + +dn: uid=jdoe,ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +uid: jdoe +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectclass: uidObject +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Jane Doe +sn: Doe + + +######################### +## Define destinations ## +######################### + +dn: ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Destination + +dn: ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Topic + +dn: ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Queue + +## TEST.FOO + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: TEST.FOO +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + + +## FOO.> + +dn: cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: FOO.$ +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + + +## BAR.* + +dn: cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: BAR.* +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + +####################### +## Define advisories ## +####################### + +dn: cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: ActiveMQ.Advisory.$ +objectClass: applicationProcess +objectClass: top +description: Advisory topics + +dn: cn=read,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +###################### +## Define temporary ## +###################### + +dn: ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Temp + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap.ldif new file mode 100644 index 0000000000..222c6fac39 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap.ldif @@ -0,0 +1,312 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +########################## +## Define basic objects ## +########################## + +dn: dc=apache,dc=org +objectClass: dcObject +objectClass: organization +dc: apache +o: Apache + +dn: dc=activemq,dc=apache,dc=org +objectClass: dcObject +objectClass: container +objectClass: top +cn: activemq +dc: activemq + +dn: ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: ActiveMQ + +dn: ou=Services,dc=activemq,dc=apache,dc=org +ou: Services +objectClass: organizationalUnit +objectClass: top + +dn: cn=mqbroker,ou=Services,dc=activemq,dc=apache,dc=org +cn: mqbroker +objectClass: organizationalRole +objectClass: top +objectClass: simpleSecurityObject +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +description: Bind user for MQ broker + + +################### +## Define groups ## +################### + + +dn: ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Group + +dn: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admins +member: uid=admin +objectClass: groupOfNames +objectClass: top + +dn: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: users +member: uid=jdoe +objectClass: groupOfNames +objectClass: top + + +################## +## Define users ## +################## + + +dn: ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: User + +dn: uid=admin,ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +uid: admin +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectclass: uidObject +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Admin +sn: Admin + + +dn: uid=jdoe,ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +uid: jdoe +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectclass: uidObject +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Jane Doe +sn: Doe + + +######################### +## Define destinations ## +######################### + +dn: ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Destination + +dn: ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Topic + +dn: ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Queue + +## TEST.FOO + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: TEST.FOO +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org + +## TEST.FOOBAR + +dn: cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: TEST.BAR +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: uid=jdoe,ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=notthere,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.FOOBAR,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: uid=jdoe,ou=User,ou=ActiveMQ,dc=activemq,dc=apache,dc=org + +## FOO.> + +dn: cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: FOO.$ +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=FOO.$,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org + +## BAR.* + +dn: cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: BAR.* +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +description: Admin privilege group, members are roles +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=BAR.*,ou=Queue,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org + +####################### +## Define advisories ## +####################### + +dn: cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: ActiveMQ.Advisory.$ +objectClass: applicationProcess +objectClass: top +description: Advisory topics + +dn: cn=read,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,cn=ActiveMQ.Advisory.$,ou=Topic,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +###################### +## Define temporary ## +###################### + +dn: ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: organizationalUnit +objectClass: top +ou: Temp + +dn: cn=read,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: read +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=write,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: write +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,ou=Temp,ou=Destination,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +cn: admin +member: cn=admins,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +member: cn=users,ou=Group,ou=ActiveMQ,dc=activemq,dc=apache,dc=org +objectClass: groupOfNames +objectClass: top + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap.xml new file mode 100644 index 0000000000..1c34783e9e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-openldap.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-sslcontext.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-sslcontext.xml new file mode 100644 index 0000000000..2297b2c940 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq-sslcontext.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq.ldif b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq.ldif new file mode 100644 index 0000000000..e9d1e42dc7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/activemq.ldif @@ -0,0 +1,241 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + + +########################## +## Define basic objects ## +########################## + +# Uncomment if adding to open ldap +#dn: ou=system +#objectclass: organizationalUnit +#objectclass: top +#ou: system + +dn: ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: ActiveMQ + +dn: ou=Services,ou=system +ou: Services +objectClass: organizationalUnit +objectClass: top + +dn: cn=mqbroker,ou=Services,ou=system +cn: mqbroker +objectClass: organizationalRole +objectClass: top +objectClass: simpleSecurityObject +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +description: Bind user for MQ broker + + +################### +## Define groups ## +################### + + +dn: ou=Group,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Group + +dn: cn=admins,ou=Group,ou=ActiveMQ,ou=system +cn: admins +member: uid=admin +objectClass: groupOfNames +objectClass: top + +dn: cn=users,ou=Group,ou=ActiveMQ,ou=system +cn: users +member: uid=jdoe +objectClass: groupOfNames +objectClass: top + + +################## +## Define users ## +################## + + +dn: ou=User,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: User + +dn: uid=admin,ou=User,ou=ActiveMQ,ou=system +uid: admin +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectClass: account +objectClass: simpleSecurityObject +objectClass: top + + +dn: uid=jdoe,ou=User,ou=ActiveMQ,ou=system +uid: jdoe +userPassword: {SSHA}YvMAkkd66cDecNoejo8jnw5uUUBziyl0 +objectclass: inetOrgPerson +objectclass: organizationalPerson +objectclass: person +objectclass: top +cn: Jane Doe +sn: Doe + + +######################### +## Define destinations ## +######################### + +dn: ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Destination + +dn: ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Topic + +dn: ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +objectClass: organizationalUnit +objectClass: top +ou: Queue + +## TEST.FOO + +dn: cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: TEST.FOO +description: A queue +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.FOO,ou=Queue,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + +## TEST.BAR + +dn: cn=TEST.BAR,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: TEST.BAR +description: A topic +objectClass: applicationProcess +objectClass: top + +dn: cn=admin,cn=TEST.BAR,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +description: Admin privilege group, members are roles +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=read,cn=TEST.BAR,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=users +member: cn=admins +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=TEST.BAR,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: write +objectClass: groupOfNames +objectClass: top +member: cn=users +member: cn=admins + + +####################### +## Define advisories ## +####################### + +dn: cn=ActiveMQ.Advisory,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: ActiveMQ.Advisory +objectClass: applicationProcess +objectClass: top +description: Advisory topics + +dn: cn=read,cn=ActiveMQ.Advisory,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=ActiveMQ.Advisory,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: write +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,cn=ActiveMQ.Advisory,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +###################### +## Define temporary ## +###################### + +dn: cn=ActiveMQ.Temp,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: ActiveMQ.Temp +objectClass: applicationProcess +objectClass: top +description: Temporary destinations + +dn: cn=read,cn=ActiveMQ.Temp,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: read +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=write,cn=ActiveMQ.Temp,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: write +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + +dn: cn=admin,cn=ActiveMQ.Temp,ou=Topic,ou=Destination,ou=ActiveMQ,ou=system +cn: admin +member: cn=admins +member: cn=users +objectClass: groupOfNames +objectClass: top + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker1.ks b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker1.ks new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker1.ts b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker1.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker1.xml new file mode 100644 index 0000000000..190f701c5a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker1.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker2.ks b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker2.ks new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker2.ts b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker2.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker2.xml new file mode 100644 index 0000000000..946b04dfe3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/broker2.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/client.ks b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/client.ks new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/client.ts b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/client.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/dos-broker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/dos-broker.xml new file mode 100644 index 0000000000..beffe49dd6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/dos-broker.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/groups.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/groups.properties new file mode 100644 index 0000000000..0898ea4c90 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/groups.properties @@ -0,0 +1,21 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +admins=system,sslclient,client,broker1,broker2 +tempDestinationAdmins=system,user,sslclient,client,broker1,broker2 +users=system,user,sslclient,client,broker1,broker2 +guests=guest diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker-guest-no-creds-only.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker-guest-no-creds-only.xml new file mode 100644 index 0000000000..6ad1e72c2f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker-guest-no-creds-only.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker-guest.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker-guest.xml new file mode 100644 index 0000000000..c8474a349e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker-guest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker.xml new file mode 100644 index 0000000000..c36fec53e6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/jaas-broker.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/ldap-spring.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/ldap-spring.xml new file mode 100644 index 0000000000..aa6b086c64 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/ldap-spring.xml @@ -0,0 +1,213 @@ + + + + + + + + + + simple + uid=admin,ou=system + secret + + + + + + + + + + + + example.com + + + + + + + + + + + + + + false + false + + + + + + + + + + + + + + + + + + + + + + + example + dc=example,dc=com + + + dc + ou + objectClass + krb5PrincipalName + uid + + + + + objectClass: top + objectClass: domain + objectClass: extensibleObject + dc: example + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-anonymous-broker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-anonymous-broker.xml new file mode 100644 index 0000000000..b9ebb53147 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-anonymous-broker.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-auth-broker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-auth-broker.xml new file mode 100644 index 0000000000..b6827283a8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-auth-broker.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-auth-separator.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-auth-separator.xml new file mode 100644 index 0000000000..65ed69131f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/simple-auth-separator.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/sslcontext-client.ts b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/sslcontext-client.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/sslcontext-keystore.ks b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/sslcontext-keystore.ks new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users.properties new file mode 100644 index 0000000000..cf72413658 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users.properties @@ -0,0 +1,21 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +system=manager +user=password +guest=password +sslclient=CN=localhost, OU=activemq.org, O=activemq.org, L=LA, ST=CA, C=US \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users1.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users1.properties new file mode 100644 index 0000000000..14cb896047 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users1.properties @@ -0,0 +1,19 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +client=CN=client, OU=activemq, O=apache +broker2=CN=broker2, OU=activemq, O=apache \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users2.properties b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users2.properties new file mode 100644 index 0000000000..c13864dff6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/security/users2.properties @@ -0,0 +1,19 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +client=CN=client, OU=activemq, O=apache +broker1=CN=broker1, OU=activemq, O=apache \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/SelectorParserTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/SelectorParserTest.java new file mode 100644 index 0000000000..0ab5118a5a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/SelectorParserTest.java @@ -0,0 +1,88 @@ +/** + * 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.selector; + +import javax.jms.InvalidSelectorException; +import junit.framework.TestCase; + +import org.apache.activemq.filter.BooleanExpression; +import org.apache.activemq.filter.BooleanFunctionCallExpr; +import org.apache.activemq.filter.ComparisonExpression; +import org.apache.activemq.filter.Expression; +import org.apache.activemq.filter.LogicExpression; +import org.apache.activemq.filter.PropertyExpression; +import org.apache.activemq.filter.XPathExpression; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class SelectorParserTest extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(SelectorParserTest.class); + + public void testFunctionCall() throws Exception { + Object filter = parse("REGEX('sales.*', group)"); + assertTrue("expected type", filter instanceof BooleanFunctionCallExpr); + LOG.info("function exp:" + filter); + + // non existent function + try { + parse("DoesNotExist('sales.*', group)"); + fail("expect ex on non existent function"); + } catch (InvalidSelectorException expected) {} + + } + + public void testParseXPath() throws Exception { + BooleanExpression filter = parse("XPATH '//title[@lang=''eng'']'"); + assertTrue("Created XPath expression", filter instanceof XPathExpression); + LOG.info("Expression: " + filter); + } + + public void testParseWithParensAround() throws Exception { + String[] values = {"x = 1 and y = 2", "(x = 1) and (y = 2)", "((x = 1) and (y = 2))"}; + + for (int i = 0; i < values.length; i++) { + String value = values[i]; + LOG.info("Parsing: " + value); + + BooleanExpression andExpression = parse(value); + assertTrue("Created LogicExpression expression", andExpression instanceof LogicExpression); + LogicExpression logicExpression = (LogicExpression)andExpression; + Expression left = logicExpression.getLeft(); + Expression right = logicExpression.getRight(); + + assertTrue("Left is a binary filter", left instanceof ComparisonExpression); + assertTrue("Right is a binary filter", right instanceof ComparisonExpression); + ComparisonExpression leftCompare = (ComparisonExpression)left; + ComparisonExpression rightCompare = (ComparisonExpression)right; + assertPropertyExpression("left", leftCompare.getLeft(), "x"); + assertPropertyExpression("right", rightCompare.getLeft(), "y"); + } + } + + protected void assertPropertyExpression(String message, Expression expression, String expected) { + assertTrue(message + ". Must be PropertyExpression", expression instanceof PropertyExpression); + PropertyExpression propExp = (PropertyExpression)expression; + assertEquals(message + ". Property name", expected, propExp.getName()); + } + + protected BooleanExpression parse(String text) throws Exception { + return SelectorParser.parse(text); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/SelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/SelectorTest.java new file mode 100644 index 0000000000..8279ae4852 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/SelectorTest.java @@ -0,0 +1,397 @@ +/** + * 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.selector; + +import javax.jms.InvalidSelectorException; +import javax.jms.JMSException; +import javax.jms.Message; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.filter.BooleanExpression; +import org.apache.activemq.filter.MessageEvaluationContext; + +/** + * + */ +public class SelectorTest extends TestCase { + + public void testBooleanSelector() throws Exception { + Message message = createMessage(); + + assertSelector(message, "(trueProp OR falseProp) AND trueProp", true); + assertSelector(message, "(trueProp OR falseProp) AND falseProp", false); + assertSelector(message, "trueProp", true); + + } + + public void testXPathSelectors() throws Exception { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + + message.setJMSType("xml"); + message.setText("b"); + + assertSelector(message, "XPATH 'root/a'", true); + assertSelector(message, "XPATH '//root/b'", true); + assertSelector(message, "XPATH 'root/c'", false); + assertSelector(message, "XPATH '//root/b/text()=\"b\"'", true); + assertSelector(message, "XPATH '//root/b=\"b\"'", true); + assertSelector(message, "XPATH '//root/b=\"c\"'", false); + assertSelector(message, "XPATH '//root/b!=\"c\"'", true); + + assertSelector(message, "XPATH '//root/*[@key=''second'']'", true); + assertSelector(message, "XPATH '//root/*[@key=''third'']'", false); + assertSelector(message, "XPATH '//root/a[@key=''first'']'", true); + assertSelector(message, "XPATH '//root/a[@num=1]'", true); + assertSelector(message, "XPATH '//root/a[@key=''second'']'", false); + + assertSelector(message, "XPATH '/root/*[@key=''first'' or @key=''third'']'", true); + assertSelector(message, "XPATH '//root/*[@key=''third'' or @key=''forth'']'", false); + + assertSelector(message, "XPATH '/root/b=''b'' and /root/b[@key=''second'']'", true); + assertSelector(message, "XPATH '/root/b=''b'' and /root/b[@key=''first'']'", false); + + assertSelector(message, "XPATH 'not(//root/a)'", false); + assertSelector(message, "XPATH 'not(//root/c)'", true); + assertSelector(message, "XPATH '//root/a[not(@key=''first'')]'", false); + assertSelector(message, "XPATH '//root/a[not(not(@key=''first''))]'", true); + + assertSelector(message, "XPATH 'string(//root/b)'", true); + assertSelector(message, "XPATH 'string(//root/a)'", false); + + assertSelector(message, "XPATH 'sum(//@num) < 10'", true); + assertSelector(message, "XPATH 'sum(//@num) > 10'", false); + + assertSelector(message, "XPATH '//root/a[@num > 1]'", false); + assertSelector(message, "XPATH '//root/b[@num > 1]'", true); + + } + + public void testJMSPropertySelectors() throws Exception { + Message message = createMessage(); + message.setJMSType("selector-test"); + message.setJMSMessageID("id:test:1:1:1:1"); + + assertSelector(message, "JMSType = 'selector-test'", true); + assertSelector(message, "JMSType = 'crap'", false); + + assertSelector(message, "JMSMessageID = 'id:test:1:1:1:1'", true); + assertSelector(message, "JMSMessageID = 'id:not-test:1:1:1:1'", false); + + message = createMessage(); + message.setJMSType("1001"); + + assertSelector(message, "JMSType='1001'", true); + assertSelector(message, "JMSType='1001' OR JMSType='1002'", true); + assertSelector(message, "JMSType = 'crap'", false); + } + + public void testBasicSelectors() throws Exception { + Message message = createMessage(); + + assertSelector(message, "name = 'James'", true); + assertSelector(message, "rank > 100", true); + assertSelector(message, "rank >= 123", true); + assertSelector(message, "rank >= 124", false); + + } + + public void testPropertyTypes() throws Exception { + Message message = createMessage(); + assertSelector(message, "byteProp = 123", true); + assertSelector(message, "byteProp = 10", false); + assertSelector(message, "byteProp2 = 33", true); + assertSelector(message, "byteProp2 = 10", false); + + assertSelector(message, "shortProp = 123", true); + assertSelector(message, "shortProp = 10", false); + + assertSelector(message, "shortProp = 123", true); + assertSelector(message, "shortProp = 10", false); + + assertSelector(message, "intProp = 123", true); + assertSelector(message, "intProp = 10", false); + + assertSelector(message, "longProp = 123", true); + assertSelector(message, "longProp = 10", false); + + assertSelector(message, "floatProp = 123", true); + assertSelector(message, "floatProp = 10", false); + + assertSelector(message, "doubleProp = 123", true); + assertSelector(message, "doubleProp = 10", false); + } + + public void testAndSelectors() throws Exception { + Message message = createMessage(); + + assertSelector(message, "name = 'James' and rank < 200", true); + assertSelector(message, "name = 'James' and rank > 200", false); + assertSelector(message, "name = 'Foo' and rank < 200", false); + assertSelector(message, "unknown = 'Foo' and anotherUnknown < 200", false); + } + + public void testOrSelectors() throws Exception { + Message message = createMessage(); + + assertSelector(message, "name = 'James' or rank < 200", true); + assertSelector(message, "name = 'James' or rank > 200", true); + assertSelector(message, "name = 'Foo' or rank < 200", true); + assertSelector(message, "name = 'Foo' or rank > 200", false); + assertSelector(message, "unknown = 'Foo' or anotherUnknown < 200", false); + } + + public void testPlus() throws Exception { + Message message = createMessage(); + + assertSelector(message, "rank + 2 = 125", true); + assertSelector(message, "(rank + 2) = 125", true); + assertSelector(message, "125 = (rank + 2)", true); + assertSelector(message, "rank + version = 125", true); + assertSelector(message, "rank + 2 < 124", false); + assertSelector(message, "name + '!' = 'James!'", true); + } + + public void testMinus() throws Exception { + Message message = createMessage(); + + assertSelector(message, "rank - 2 = 121", true); + assertSelector(message, "rank - version = 121", true); + assertSelector(message, "rank - 2 > 122", false); + } + + public void testMultiply() throws Exception { + Message message = createMessage(); + + assertSelector(message, "rank * 2 = 246", true); + assertSelector(message, "rank * version = 246", true); + assertSelector(message, "rank * 2 < 130", false); + } + + public void testDivide() throws Exception { + Message message = createMessage(); + + assertSelector(message, "rank / version = 61.5", true); + assertSelector(message, "rank / 3 > 100.0", false); + assertSelector(message, "rank / 3 > 100", false); + assertSelector(message, "version / 2 = 1", true); + + } + + public void testBetween() throws Exception { + Message message = createMessage(); + + assertSelector(message, "rank between 100 and 150", true); + assertSelector(message, "rank between 10 and 120", false); + } + + public void testIn() throws Exception { + Message message = createMessage(); + + assertSelector(message, "name in ('James', 'Bob', 'Gromit')", true); + assertSelector(message, "name in ('Bob', 'James', 'Gromit')", true); + assertSelector(message, "name in ('Gromit', 'Bob', 'James')", true); + + assertSelector(message, "name in ('Gromit', 'Bob', 'Cheddar')", false); + assertSelector(message, "name not in ('Gromit', 'Bob', 'Cheddar')", true); + } + + public void testIsNull() throws Exception { + Message message = createMessage(); + + assertSelector(message, "dummy is null", true); + assertSelector(message, "dummy is not null", false); + assertSelector(message, "name is not null", true); + assertSelector(message, "name is null", false); + } + + public void testLike() throws Exception { + Message message = createMessage(); + message.setStringProperty("modelClassId", "com.whatever.something.foo.bar"); + message.setStringProperty("modelInstanceId", "170"); + message.setStringProperty("modelRequestError", "abc"); + message.setStringProperty("modelCorrelatedClientId", "whatever"); + + assertSelector(message, "modelClassId LIKE 'com.whatever.something.%' AND modelInstanceId = '170' AND (modelRequestError IS NULL OR modelCorrelatedClientId = 'whatever')", + true); + + message.setStringProperty("modelCorrelatedClientId", "shouldFailNow"); + + assertSelector(message, "modelClassId LIKE 'com.whatever.something.%' AND modelInstanceId = '170' AND (modelRequestError IS NULL OR modelCorrelatedClientId = 'whatever')", + false); + + message = createMessage(); + message.setStringProperty("modelClassId", "com.whatever.something.foo.bar"); + message.setStringProperty("modelInstanceId", "170"); + message.setStringProperty("modelCorrelatedClientId", "shouldNotMatch"); + + assertSelector(message, "modelClassId LIKE 'com.whatever.something.%' AND modelInstanceId = '170' AND (modelRequestError IS NULL OR modelCorrelatedClientId = 'whatever')", + true); + } + + /** + * Test cases from Mats Henricson + */ + public void testMatsHenricsonUseCases() throws Exception { + Message message = createMessage(); + assertSelector(message, "SessionserverId=1870414179", false); + + message.setLongProperty("SessionserverId", 1870414179); + assertSelector(message, "SessionserverId=1870414179", true); + + message.setLongProperty("SessionserverId", 1234); + assertSelector(message, "SessionserverId=1870414179", false); + + assertSelector(message, "Command NOT IN ('MirrorLobbyRequest', 'MirrorLobbyReply')", false); + + message.setStringProperty("Command", "Cheese"); + assertSelector(message, "Command NOT IN ('MirrorLobbyRequest', 'MirrorLobbyReply')", true); + + message.setStringProperty("Command", "MirrorLobbyRequest"); + assertSelector(message, "Command NOT IN ('MirrorLobbyRequest', 'MirrorLobbyReply')", false); + message.setStringProperty("Command", "MirrorLobbyReply"); + assertSelector(message, "Command NOT IN ('MirrorLobbyRequest', 'MirrorLobbyReply')", false); + } + + public void testFloatComparisons() throws Exception { + Message message = createMessage(); + + assertSelector(message, "1.0 < 1.1", true); + assertSelector(message, "-1.1 < 1.0", true); + assertSelector(message, "1.0E1 < 1.1E1", true); + assertSelector(message, "-1.1E1 < 1.0E1", true); + + assertSelector(message, "1. < 1.1", true); + assertSelector(message, "-1.1 < 1.", true); + assertSelector(message, "1.E1 < 1.1E1", true); + assertSelector(message, "-1.1E1 < 1.E1", true); + + assertSelector(message, ".1 < .5", true); + assertSelector(message, "-.5 < .1", true); + assertSelector(message, ".1E1 < .5E1", true); + assertSelector(message, "-.5E1 < .1E1", true); + + assertSelector(message, "4E10 < 5E10", true); + assertSelector(message, "5E8 < 5E10", true); + assertSelector(message, "-4E10 < 2E10", true); + assertSelector(message, "-5E8 < 2E2", true); + assertSelector(message, "4E+10 < 5E+10", true); + assertSelector(message, "4E-10 < 5E-10", true); + } + + public void testStringQuoteParsing() throws Exception { + Message message = createMessage(); + assertSelector(message, "quote = '''In God We Trust'''", true); + } + + public void testLikeComparisons() throws Exception { + Message message = createMessage(); + + assertSelector(message, "quote LIKE '''In G_d We Trust'''", true); + assertSelector(message, "quote LIKE '''In Gd_ We Trust'''", false); + assertSelector(message, "quote NOT LIKE '''In G_d We Trust'''", false); + assertSelector(message, "quote NOT LIKE '''In Gd_ We Trust'''", true); + + assertSelector(message, "foo LIKE '%oo'", true); + assertSelector(message, "foo LIKE '%ar'", false); + assertSelector(message, "foo NOT LIKE '%oo'", false); + assertSelector(message, "foo NOT LIKE '%ar'", true); + + assertSelector(message, "foo LIKE '!_%' ESCAPE '!'", true); + assertSelector(message, "quote LIKE '!_%' ESCAPE '!'", false); + assertSelector(message, "foo NOT LIKE '!_%' ESCAPE '!'", false); + assertSelector(message, "quote NOT LIKE '!_%' ESCAPE '!'", true); + + assertSelector(message, "punctuation LIKE '!#$&()*+,-./:;<=>?@[\\]^`{|}~'", true); + } + + public void testInvalidSelector() throws Exception { + Message message = createMessage(); + assertInvalidSelector(message, "3+5"); + assertInvalidSelector(message, "True AND 3+5"); + assertInvalidSelector(message, "=TEST 'test'"); + } + + public void testFunctionSelector() throws Exception { + Message message = createMessage(); + assertSelector(message, "REGEX('1870414179', SessionserverId)", false); + message.setLongProperty("SessionserverId", 1870414179); + assertSelector(message, "REGEX('1870414179', SessionserverId)", true); + assertSelector(message, "REGEX('[0-9]*', SessionserverId)", true); + assertSelector(message, "REGEX('^[1-8]*$', SessionserverId)", false); + assertSelector(message, "REGEX('^[1-8]*$', SessionserverId)", false); + + assertSelector(message, "INLIST(SPLIT('Tom,Dick,George',','), name)", false); + assertSelector(message, "INLIST(SPLIT('Tom,James,George',','), name)", true); + + assertSelector(message, "INLIST(MAKELIST('Tom','Dick','George'), name)", false); + assertSelector(message, "INLIST(MAKELIST('Tom','James','George'), name)", true); + + assertSelector(message, "REGEX('connection1111', REPLACE(JMSMessageID,':',''))", true); + } + + protected Message createMessage() throws JMSException { + Message message = createMessage("FOO.BAR"); + message.setJMSType("selector-test"); + message.setJMSMessageID("connection:1:1:1:1"); + message.setObjectProperty("name", "James"); + message.setObjectProperty("location", "London"); + + message.setByteProperty("byteProp", (byte)123); + message.setByteProperty("byteProp2", (byte)33); + message.setShortProperty("shortProp", (short)123); + message.setIntProperty("intProp", 123); + message.setLongProperty("longProp", 123); + message.setFloatProperty("floatProp", 123); + message.setDoubleProperty("doubleProp", 123); + + message.setIntProperty("rank", 123); + message.setIntProperty("version", 2); + message.setStringProperty("quote", "'In God We Trust'"); + message.setStringProperty("foo", "_foo"); + message.setStringProperty("punctuation", "!#$&()*+,-./:;<=>?@[\\]^`{|}~"); + message.setBooleanProperty("trueProp", true); + message.setBooleanProperty("falseProp", false); + return message; + } + + protected void assertInvalidSelector(Message message, String text) throws JMSException { + try { + SelectorParser.parse(text); + fail("Created a valid selector"); + } catch (InvalidSelectorException e) { + } + } + + protected void assertSelector(Message message, String text, boolean expected) throws JMSException { + BooleanExpression selector = SelectorParser.parse(text); + assertTrue("Created a valid selector", selector != null); + MessageEvaluationContext context = new MessageEvaluationContext(); + context.setMessageReference((org.apache.activemq.command.Message)message); + boolean value = selector.matches(context); + assertEquals("Selector for: " + text, expected, value); + } + + protected Message createMessage(String subject) throws JMSException { + ActiveMQMessage message = new ActiveMQMessage(); + message.setJMSDestination(new ActiveMQTopic(subject)); + return message; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/UnknownHandlingSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/UnknownHandlingSelectorTest.java new file mode 100644 index 0000000000..5c9a8eecf8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/selector/UnknownHandlingSelectorTest.java @@ -0,0 +1,182 @@ +/** + * 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.selector; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import javax.jms.JMSException; +import javax.jms.Message; + +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.filter.BooleanExpression; +import org.apache.activemq.filter.MessageEvaluationContext; +import org.junit.Before; +import org.junit.Test; + +public class UnknownHandlingSelectorTest { + + private Message message; + + @Before + public void setUp() throws Exception { + message = new ActiveMQMessage(); + message.setJMSDestination(new ActiveMQTopic("FOO.BAR")); + message.setJMSType("selector-test"); + message.setJMSMessageID("connection:1:1:1:1"); + message.setBooleanProperty("trueProp", true); + message.setBooleanProperty("falseProp", false); + message.setObjectProperty("nullProp", null); + } + + /** + * | NOT + * +------+------ + * | T | F + * | F | T + * | U | U + * +------+------- + */ + @Test + public void notEvaluation() throws Exception { + assertSelector("not(trueProp)", false); + assertSelector("not(falseProp)", true); + assertSelector("not(unknownProp)", false); + } + + /** + * | AND | T | F | U + * +------+-------+-------+------- + * | T | T | F | U + * | F | F | F | F + * | U | U | F | U + * +------+-------+-------+------- + */ + @Test + public void andEvaluation() throws Exception { + assertSelectorEvaluatesToTrue("trueProp AND trueProp"); + assertSelectorEvaluatesToFalse("trueProp AND falseProp"); + assertSelectorEvaluatesToFalse("falseProp AND trueProp"); + assertSelectorEvaluatesToFalse("falseProp AND falseProp"); + assertSelectorEvaluatesToFalse("falseProp AND unknownProp"); + assertSelectorEvaluatesToFalse("unknownProp AND falseProp"); + assertSelectorEvaluatesToUnknown("trueProp AND unknownProp"); + assertSelectorEvaluatesToUnknown("unknownProp AND trueProp"); + assertSelectorEvaluatesToUnknown("unknownProp AND unknownProp"); + } + + /** + * | OR | T | F | U + * +------+-------+-------+-------- + * | T | T | T | T + * | F | T | F | U + * | U | T | U | U + * +------+-------+-------+------- + */ + @Test + public void orEvaluation() throws Exception { + assertSelectorEvaluatesToTrue("trueProp OR trueProp"); + assertSelectorEvaluatesToTrue("trueProp OR falseProp"); + assertSelectorEvaluatesToTrue("falseProp OR trueProp"); + assertSelectorEvaluatesToTrue("trueProp OR unknownProp"); + assertSelectorEvaluatesToTrue("unknownProp OR trueProp"); + assertSelectorEvaluatesToFalse("falseProp OR falseProp"); + assertSelectorEvaluatesToUnknown("falseProp OR unknownProp"); + assertSelectorEvaluatesToUnknown("unknownProp OR falseProp"); + assertSelectorEvaluatesToUnknown("unknownProp OR unknownProp"); + } + + @Test + public void comparisonWithUnknownShouldEvaluateToUnknown() throws Exception { + assertSelectorEvaluatesToUnknown("unknownProp = 0"); + assertSelectorEvaluatesToUnknown("unknownProp > 0"); + assertSelectorEvaluatesToUnknown("unknownProp >= 0"); + assertSelectorEvaluatesToUnknown("unknownProp < 0"); + assertSelectorEvaluatesToUnknown("unknownProp <= 0"); + assertSelectorEvaluatesToUnknown("unknownProp <> 0"); + assertSelectorEvaluatesToUnknown("unknownProp LIKE 'zero'"); + assertSelectorEvaluatesToUnknown("unknownProp NOT LIKE 'zero'"); + assertSelectorEvaluatesToUnknown("unknownProp IN ('zero')"); + assertSelectorEvaluatesToUnknown("unknownProp NOT IN ('zero')"); + assertSelectorEvaluatesToUnknown("unknownProp BETWEEN 1 AND 2"); + assertSelectorEvaluatesToUnknown("unknownProp NOT BETWEEN 1 AND 2"); + } + + @Test + public void comparisonWithNullPropShouldEvaluateToUnknown() throws Exception { + assertSelectorEvaluatesToUnknown("nullProp = 0"); + assertSelectorEvaluatesToUnknown("nullProp > 0"); + assertSelectorEvaluatesToUnknown("nullProp >= 0"); + assertSelectorEvaluatesToUnknown("nullProp < 0"); + assertSelectorEvaluatesToUnknown("nullProp <= 0"); + assertSelectorEvaluatesToUnknown("nullProp <> 0"); + assertSelectorEvaluatesToUnknown("nullProp LIKE 'zero'"); + assertSelectorEvaluatesToUnknown("nullProp NOT LIKE 'zero'"); + assertSelectorEvaluatesToUnknown("nullProp IN ('zero')"); + assertSelectorEvaluatesToUnknown("nullProp NOT IN ('zero')"); + assertSelectorEvaluatesToUnknown("nullProp BETWEEN 1 AND 2"); + assertSelectorEvaluatesToUnknown("nullProp NOT BETWEEN 1 AND 2"); + } + + @Test + public void isNullIsNotNull() throws Exception { + assertSelectorEvaluatesToTrue("unknownProp IS NULL"); + assertSelectorEvaluatesToTrue("nullProp IS NULL"); + assertSelectorEvaluatesToFalse("trueProp IS NULL"); + assertSelectorEvaluatesToFalse("unknownProp IS NOT NULL"); + assertSelectorEvaluatesToFalse("nullProp IS NOT NULL"); + assertSelectorEvaluatesToTrue("trueProp IS NOT NULL"); + } + + @Test + public void arithmeticWithNull() throws Exception { + assertSelectorEvaluatesToUnknown("-unknownProp = 0"); + assertSelectorEvaluatesToUnknown("+unknownProp = 0"); + assertSelectorEvaluatesToUnknown("unknownProp * 2 = 0"); + assertSelectorEvaluatesToUnknown("unknownProp / 2 = 0"); + assertSelectorEvaluatesToUnknown("unknownProp + 2 = 0"); + assertSelectorEvaluatesToUnknown("unknownProp - 2 = 0"); + } + + protected void assertSelectorEvaluatesToUnknown(String selector) throws JMSException { + assertSelector(selector, false); + assertSelector(not(selector), false); + } + protected void assertSelectorEvaluatesToTrue(String selector) throws JMSException { + assertSelector(selector, true); + assertSelector(not(selector), false); + } + + protected void assertSelectorEvaluatesToFalse(String selector) throws JMSException { + assertSelector(selector, false); + assertSelector(not(selector), true); + } + + protected void assertSelector(String text, boolean matches) throws JMSException { + BooleanExpression selector = SelectorParser.parse(text); + assertTrue("Created a valid selector", selector != null); + MessageEvaluationContext context = new MessageEvaluationContext(); + context.setMessageReference((org.apache.activemq.command.Message)message); + boolean value = selector.matches(context); + assertEquals("Selector for: " + text, matches, value); + } + + private static String not(String selector) { + return "not(" + selector + ")"; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/ActiveMQConnectionFactoryFactoryBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/ActiveMQConnectionFactoryFactoryBeanTest.java new file mode 100644 index 0000000000..b3bc597a3a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/ActiveMQConnectionFactoryFactoryBeanTest.java @@ -0,0 +1,94 @@ +/** + * + * 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.spring; + +import java.util.Arrays; + +import junit.framework.TestCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ActiveMQConnectionFactoryFactoryBeanTest extends TestCase { + private static final transient Logger LOG = LoggerFactory.getLogger(ActiveMQConnectionFactoryFactoryBeanTest.class); + + private ActiveMQConnectionFactoryFactoryBean factory; + + + public void testSingleTcpURL() throws Exception { + factory.setTcpHostAndPort("tcp://localhost:61616"); + assertCreatedURL("failover:(tcp://localhost:61616)"); + } + + public void testSingleTcpURLWithInactivityTimeout() throws Exception { + factory.setTcpHostAndPort("tcp://localhost:61616"); + factory.setMaxInactivityDuration(60000L); + assertCreatedURL("failover:(tcp://localhost:61616?wireFormat.maxInactivityDuration=60000)"); + } + + public void testSingleTcpURLWithInactivityTimeoutAndTcpNoDelay() throws Exception { + factory.setTcpHostAndPort("tcp://localhost:61616"); + factory.setMaxInactivityDuration(50000L); + factory.setTcpProperties("tcpNoDelayEnabled=true"); + assertCreatedURL("failover:(tcp://localhost:61616?wireFormat.maxInactivityDuration=50000&tcpNoDelayEnabled=true)"); + } + + public void testSingleTcpURLWithInactivityTimeoutAndMaxReconnectDelay() throws Exception { + factory.setTcpHostAndPort("tcp://localhost:61616"); + factory.setMaxInactivityDuration(60000L); + factory.setMaxReconnectDelay(50000L); + assertCreatedURL("failover:(tcp://localhost:61616?wireFormat.maxInactivityDuration=60000)?maxReconnectDelay=50000"); + } + + public void testSingleTcpURLWithInactivityTimeoutAndMaxReconnectDelayAndFailoverProperty() throws Exception { + factory.setTcpHostAndPort("tcp://localhost:61616"); + factory.setMaxInactivityDuration(40000L); + factory.setMaxReconnectDelay(30000L); + factory.setFailoverProperties("useExponentialBackOff=false"); + + assertCreatedURL("failover:(tcp://localhost:61616?wireFormat.maxInactivityDuration=40000)?maxReconnectDelay=30000&useExponentialBackOff=false"); + } + + public void testMultipleTcpURLsWithInactivityTimeoutAndMaxReconnectDelayAndFailoverProperty() throws Exception { + factory.setTcpHostAndPorts(Arrays.asList(new String[] {"tcp://localhost:61618", "tcp://foo:61619"})); + factory.setMaxInactivityDuration(40000L); + factory.setMaxReconnectDelay(30000L); + factory.setFailoverProperties("useExponentialBackOff=false"); + + assertCreatedURL("failover:(tcp://localhost:61618?wireFormat.maxInactivityDuration=40000,tcp://foo:61619?wireFormat.maxInactivityDuration=40000)?maxReconnectDelay=30000&useExponentialBackOff=false"); + } + + protected void assertCreatedURL(String expectedURL) throws Exception { + String url = factory.getBrokerURL(); + LOG.debug("Generated URL: " + url); + + assertEquals("URL", expectedURL, url); + Object value = factory.getObject(); + assertTrue("Value should be an ActiveMQConnectionFactory", value instanceof ActiveMQConnectionFactory); + ActiveMQConnectionFactory connectionFactory = (ActiveMQConnectionFactory) value; + String brokerURL = connectionFactory.getBrokerURL(); + assertEquals("brokerURL", expectedURL, brokerURL); + } + + @Override + protected void setUp() throws Exception { + factory = new ActiveMQConnectionFactoryFactoryBean(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/ConsumerBean.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/ConsumerBean.java new file mode 100644 index 0000000000..8f22c33d40 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/ConsumerBean.java @@ -0,0 +1,167 @@ +/** + * 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.spring; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Message; +import javax.jms.MessageListener; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConsumerBean extends Assert implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(ConsumerBean.class); + private final List messages = new ArrayList(); + private boolean verbose; + + /** + * Constructor. + */ + public ConsumerBean() { + } + + /** + * @return all the messages on the list so far, clearing the buffer + */ + public List flushMessages() { + List answer = null; + synchronized(messages) { + answer = new ArrayList(messages); + messages.clear(); + } + return answer; + } + + /** + * Method implemented from MessageListener interface. + * + * @param message + */ + @Override + public void onMessage(Message message) { + synchronized (messages) { + messages.add(message); + if (verbose) { + LOG.info("Received: " + message); + } + messages.notifyAll(); + } + } + + /** + * Use to wait for a single message to arrive. + */ + public void waitForMessageToArrive() { + LOG.info("Waiting for message to arrive"); + + long start = System.currentTimeMillis(); + + try { + if (hasReceivedMessage()) { + synchronized (messages) { + messages.wait(4000); + } + } + } catch (InterruptedException e) { + LOG.info("Caught: " + e); + } + long end = System.currentTimeMillis() - start; + + LOG.info("End of wait for " + end + " millis"); + } + + /** + * Used to wait for a message to arrive given a particular message count. + * + * @param messageCount + */ + + public void waitForMessagesToArrive(int messageCount){ + waitForMessagesToArrive(messageCount,120 * 1000); + } + public void waitForMessagesToArrive(int messageCount,long maxWaitTime) { + long maxRemainingMessageCount = Math.max(0, messageCount - messages.size()); + LOG.info("Waiting for (" + maxRemainingMessageCount + ") message(s) to arrive"); + long start = System.currentTimeMillis(); + long endTime = start + maxWaitTime; + while (maxRemainingMessageCount > 0) { + try { + synchronized (messages) { + messages.wait(1000); + } + if (hasReceivedMessages(messageCount) || System.currentTimeMillis() > endTime) { + break; + } + } catch (InterruptedException e) { + LOG.info("Caught: " + e); + } + maxRemainingMessageCount = Math.max(0, messageCount - messages.size()); + } + long end = System.currentTimeMillis() - start; + LOG.info("End of wait for " + end + " millis"); + } + + public void assertMessagesArrived(int total) { + waitForMessagesToArrive(total); + synchronized (messages) { + int count = messages.size(); + + assertEquals("Messages received", total, count); + } + } + + public void assertMessagesArrived(int total, long maxWaitTime) { + waitForMessagesToArrive(total,maxWaitTime); + synchronized (messages) { + int count = messages.size(); + + assertEquals("Messages received", total, count); + } + } + + public boolean isVerbose() { + return verbose; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + /** + * Identifies if the message is empty. + * + * @return + */ + protected boolean hasReceivedMessage() { + return messages.isEmpty(); + } + + /** + * Identifies if the message count has reached the total size of message. + * + * @param messageCount + * @return + */ + protected boolean hasReceivedMessages(int messageCount) { + synchronized (messages) { + return messages.size() >= messageCount; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/Spring2XmlNamespacesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/Spring2XmlNamespacesTest.java new file mode 100644 index 0000000000..ca62d01fc2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/Spring2XmlNamespacesTest.java @@ -0,0 +1,23 @@ +/** + * 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.spring; + +public class Spring2XmlNamespacesTest extends SpringTestSupport { + public void testUsingSpringXmlNamespacesWithPublicXsdLocation() throws Exception { + assertSenderConfig("spring-embedded-xbean.xml"); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/Spring2XmlNamespacesWithoutRemoteSchemaTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/Spring2XmlNamespacesWithoutRemoteSchemaTest.java new file mode 100644 index 0000000000..7a3287739e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/Spring2XmlNamespacesWithoutRemoteSchemaTest.java @@ -0,0 +1,23 @@ +/** + * 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.spring; + +public class Spring2XmlNamespacesWithoutRemoteSchemaTest extends SpringTestSupport { + public void testUsingSpring2NamespacesForANonExistingXsdDocument() throws Exception { + assertSenderConfig("spring-embedded-xbean-noversion.xml"); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringConsumer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringConsumer.java new file mode 100644 index 0000000000..118e0361c8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringConsumer.java @@ -0,0 +1,113 @@ +/** + * 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.spring; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jms.core.JmsTemplate; + +public class SpringConsumer extends ConsumerBean implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(SpringConsumer.class); + private JmsTemplate template; + private String myId = "foo"; + private Destination destination; + private Connection connection; + private Session session; + private MessageConsumer consumer; + + public void start() throws JMSException { + String selector = "next = '" + myId + "'"; + + try { + ConnectionFactory factory = template.getConnectionFactory(); + connection = factory.createConnection(); + + // we might be a reusable connection in spring + // so lets only set the client ID once if its not set + synchronized (connection) { + if (connection.getClientID() == null) { + connection.setClientID(myId); + } + } + + connection.start(); + + session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + consumer = session.createConsumer(destination, selector, false); + consumer.setMessageListener(this); + } catch (JMSException ex) { + LOG.error("", ex); + throw ex; + } + } + + public void stop() throws JMSException { + if (consumer != null) { + consumer.close(); + } + if (session != null) { + session.close(); + } + if (connection != null) { + connection.close(); + } + } + + public void onMessage(Message message) { + super.onMessage(message); + try { + message.acknowledge(); + } catch (JMSException e) { + LOG.error("Failed to acknowledge: " + e, e); + } + } + + // Properties + // ------------------------------------------------------------------------- + public Destination getDestination() { + return destination; + } + + public void setDestination(Destination destination) { + this.destination = destination; + } + + public String getMyId() { + return myId; + } + + public void setMyId(String myId) { + this.myId = myId; + } + + public JmsTemplate getTemplate() { + return template; + } + + public void setTemplate(JmsTemplate template) { + this.template = template; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringProducer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringProducer.java new file mode 100644 index 0000000000..c2bbad07c5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringProducer.java @@ -0,0 +1,79 @@ +/** + * 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.spring; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; + +public class SpringProducer { + private static final Logger LOG = LoggerFactory.getLogger(SpringProducer.class); + private JmsTemplate template; + private Destination destination; + private int messageCount = 10; + + public void start() throws JMSException { + for (int i = 0; i < messageCount; i++) { + final String text = "Text for message: " + i; + template.send(destination, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + LOG.info("Sending message: " + text); + TextMessage message = session.createTextMessage(text); + message.setStringProperty("next", "foo"); + return message; + } + }); + } + } + + public void stop() throws JMSException { + } + + // Properties + //------------------------------------------------------------------------- + + public JmsTemplate getTemplate() { + return template; + } + + public void setTemplate(JmsTemplate template) { + this.template = template; + } + + public int getMessageCount() { + return messageCount; + } + + public void setMessageCount(int messageCount) { + this.messageCount = messageCount; + } + + public Destination getDestination() { + return destination; + } + + public void setDestination(Destination destination) { + this.destination = destination; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringTest.java new file mode 100644 index 0000000000..9bea3edc40 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringTest.java @@ -0,0 +1,98 @@ +/** + * 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.spring; + +import org.apache.activemq.broker.BrokerService; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class SpringTest extends SpringTestSupport { + + /** + * Uses ActiveMQConnectionFactory to create the connection context. + * Configuration file is /resources/spring.xml + * + * @throws Exception + */ + public void testSenderWithSpringXml() throws Exception { + String config = "spring.xml"; + assertSenderConfig(config); + } + + /** + * Spring configured test that uses ActiveMQConnectionFactory for + * connection context and ActiveMQQueue for destination. Configuration + * file is /resources/spring-queue.xml. + * + * @throws Exception + */ + public void testSenderWithSpringXmlAndQueue() throws Exception { + String config = "spring-queue.xml"; + assertSenderConfig(config); + } + + /** + * Spring configured test that uses JNDI. Configuration file is + * /resources/spring-jndi.xml. + * + * @throws Exception + */ + public void testSenderWithSpringXmlUsingJNDI() throws Exception { + String config = "spring-jndi.xml"; + assertSenderConfig(config); + } + + /** + * Spring configured test where in the connection context is set to use + * an embedded broker. Configuration file is /resources/spring-embedded.xml + * and /resources/activemq.xml. + * + * @throws Exception + */ + public void testSenderWithSpringXmlEmbeddedBrokerConfiguredViaXml() throws Exception { + String config = "spring-embedded.xml"; + assertSenderConfig(config); + } + + /** + * Spring configured test case that tests the remotely deployed xsd + * http://people.apache.org/repository/org.apache.activemq/xsds/activemq-core-4.1-SNAPSHOT.xsd + * + * @throws Exception + */ + public void testSenderWithSpringXmlUsingSpring2NamespacesWithEmbeddedBrokerConfiguredViaXml() throws Exception { + String config = "spring-embedded-xbean.xml"; + assertSenderConfig(config); + } + + /** + * Spring configured test case that tests the locally generated xsd + * + * @throws Exception + */ + public void testSenderWithSpringXmlUsingSpring2NamespacesWithEmbeddedBrokerConfiguredViaXmlUsingLocalXsd() throws Exception { + String config = "spring-embedded-xbean-local.xml"; + assertSenderConfig(config); + } + + public void testStartFalse() throws Exception { + String config = "spring-start-false.xml"; + Thread.currentThread().setContextClassLoader(SpringTest.class.getClassLoader()); + context = new ClassPathXmlApplicationContext(config); + BrokerService broker = (BrokerService)context.getBean(BrokerService.class); + assertFalse("Broker is started", broker.isStarted()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringTestSupport.java new file mode 100644 index 0000000000..53ec6d9b2e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/spring/SpringTestSupport.java @@ -0,0 +1,97 @@ +/** + * 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.spring; + +import java.util.Iterator; +import java.util.List; + +import javax.jms.Message; + +import junit.framework.TestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * + */ +public class SpringTestSupport extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(SpringTest.class); + protected AbstractApplicationContext context; + protected SpringConsumer consumer; + protected SpringProducer producer; + + /** + * assert method that is used by all the test method to send and receive messages + * based on each spring configuration. + * + * @param config + * @throws Exception + */ + protected void assertSenderConfig(String config) throws Exception { + Thread.currentThread().setContextClassLoader(SpringTest.class.getClassLoader()); + context = new ClassPathXmlApplicationContext(config); + + consumer = (SpringConsumer) context.getBean("consumer"); + assertTrue("Found a valid consumer", consumer != null); + + consumer.start(); + + // Wait a little to drain any left over messages. + Thread.sleep(1000); + consumer.flushMessages(); + + producer = (SpringProducer) context.getBean("producer"); + assertTrue("Found a valid producer", producer != null); + + producer.start(); + + // lets sleep a little to give the JMS time to dispatch stuff + consumer.waitForMessagesToArrive(producer.getMessageCount()); + + // now lets check that the consumer has received some messages + List messages = consumer.flushMessages(); + LOG.info("Consumer has received messages...."); + for (Iterator iter = messages.iterator(); iter.hasNext();) { + Object message = iter.next(); + LOG.info("Received: " + message); + } + + assertEquals("Message count", producer.getMessageCount(), messages.size()); + } + + /** + * Clean up method. + * + * @throws Exception + */ + @Override + protected void tearDown() throws Exception { + if (consumer != null) { + consumer.stop(); + } + if (producer != null) { + producer.stop(); + } + + if (context != null) { + context.destroy(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/AutoStorePerDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/AutoStorePerDestinationTest.java new file mode 100644 index 0000000000..2b76a224df --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/AutoStorePerDestinationTest.java @@ -0,0 +1,42 @@ +/** + * 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.store; + +import java.util.ArrayList; +import org.apache.activemq.store.kahadb.FilteredKahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.MultiKahaDBPersistenceAdapter; + +public class AutoStorePerDestinationTest extends StorePerDestinationTest { + + // use perDestinationFlag to get multiple stores from one match all adapter + public void prepareBrokerWithMultiStore(boolean deleteAllMessages) throws Exception { + + MultiKahaDBPersistenceAdapter multiKahaDBPersistenceAdapter = new MultiKahaDBPersistenceAdapter(); + if (deleteAllMessages) { + multiKahaDBPersistenceAdapter.deleteAllMessages(); + } + ArrayList adapters = new ArrayList(); + + FilteredKahaDBPersistenceAdapter template = new FilteredKahaDBPersistenceAdapter(); + template.setPersistenceAdapter(createStore(deleteAllMessages)); + template.setPerDestination(true); + adapters.add(template); + + multiKahaDBPersistenceAdapter.setFilteredPersistenceAdapters(adapters); + brokerService = createBroker(multiKahaDBPersistenceAdapter); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/LevelDBStorePerDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/LevelDBStorePerDestinationTest.java new file mode 100644 index 0000000000..b10786cf86 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/LevelDBStorePerDestinationTest.java @@ -0,0 +1,45 @@ +/** + * 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.store; + +import org.apache.activemq.leveldb.LevelDBStore; +import org.junit.Test; + +import java.io.IOException; + +public class LevelDBStorePerDestinationTest extends StorePerDestinationTest { + + + @Override + protected PersistenceAdapter createStore(boolean delete) throws IOException { + LevelDBStore store = new LevelDBStore(); + store.setLogSize(maxFileLength); + if (delete) { + store.deleteAllMessages(); + } + return store; + } + + @Test + @Override + public void testRollbackRecovery() throws Exception {} + + @Test + @Override + public void testCommitRecovery() throws Exception {} + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/MessagePriorityTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/MessagePriorityTest.java new file mode 100644 index 0000000000..521c8991ea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/MessagePriorityTest.java @@ -0,0 +1,587 @@ +/** + * 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.store; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.broker.region.policy.StorePendingDurableSubscriberMessageStoragePolicy; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +abstract public class MessagePriorityTest extends CombinationTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(MessagePriorityTest.class); + + BrokerService broker; + PersistenceAdapter adapter; + + protected ActiveMQConnectionFactory factory; + protected Connection conn; + protected Session sess; + + public boolean useCache = true; + public int deliveryMode = Message.DEFAULT_DELIVERY_MODE; + public boolean dispatchAsync = true; + public boolean prioritizeMessages = true; + public boolean immediatePriorityDispatch = true; + public int prefetchVal = 500; + public int expireMessagePeriod = 30000; + + public int MSG_NUM = 600; + public int HIGH_PRI = 7; + public int LOW_PRI = 3; + + abstract protected PersistenceAdapter createPersistenceAdapter(boolean delete) throws Exception; + + @Override + protected void setUp() throws Exception { + broker = new BrokerService(); + broker.setBrokerName("priorityTest"); + broker.setAdvisorySupport(false); + adapter = createPersistenceAdapter(true); + broker.setPersistenceAdapter(adapter); + PolicyEntry policy = new PolicyEntry(); + policy.setPrioritizedMessages(prioritizeMessages); + policy.setUseCache(useCache); + policy.setExpireMessagesPeriod(expireMessagePeriod); + StorePendingDurableSubscriberMessageStoragePolicy durableSubPending = + new StorePendingDurableSubscriberMessageStoragePolicy(); + durableSubPending.setImmediatePriorityDispatch(immediatePriorityDispatch); + durableSubPending.setUseCache(useCache); + policy.setPendingDurableSubscriberPolicy(durableSubPending); + PolicyMap policyMap = new PolicyMap(); + policyMap.put(new ActiveMQQueue("TEST"), policy); + policyMap.put(new ActiveMQTopic("TEST"), policy); + + // do not process expired for one test + PolicyEntry ignoreExpired = new PolicyEntry(); + SharedDeadLetterStrategy ignoreExpiredStrategy = new SharedDeadLetterStrategy(); + ignoreExpiredStrategy.setProcessExpired(false); + ignoreExpired.setDeadLetterStrategy(ignoreExpiredStrategy); + policyMap.put(new ActiveMQTopic("TEST_CLEANUP_NO_PRIORITY"), ignoreExpired); + + broker.setDestinationPolicy(policyMap); + broker.start(); + broker.waitUntilStarted(); + + factory = new ActiveMQConnectionFactory("vm://priorityTest"); + ActiveMQPrefetchPolicy prefetch = new ActiveMQPrefetchPolicy(); + prefetch.setAll(prefetchVal); + factory.setPrefetchPolicy(prefetch); + factory.setWatchTopicAdvisories(false); + factory.setDispatchAsync(dispatchAsync); + conn = factory.createConnection(); + conn.setClientID("priority"); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + @Override + protected void tearDown() throws Exception { + try { + sess.close(); + conn.close(); + } catch (Exception ignored) { + } finally { + broker.stop(); + broker.waitUntilStopped(); + } + } + + public void testStoreConfigured() throws Exception { + final Queue queue = sess.createQueue("TEST"); + final Topic topic = sess.createTopic("TEST"); + + MessageProducer queueProducer = sess.createProducer(queue); + MessageProducer topicProducer = sess.createProducer(topic); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker.getRegionBroker().getDestinationMap().get(queue) != null; + } + }); + assertTrue(broker.getRegionBroker().getDestinationMap().get(queue).getMessageStore().isPrioritizedMessages()); + + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + return broker.getRegionBroker().getDestinationMap().get(topic) != null; + } + }); + assertTrue(broker.getRegionBroker().getDestinationMap().get(topic).getMessageStore().isPrioritizedMessages()); + + queueProducer.close(); + topicProducer.close(); + + } + + protected class ProducerThread extends Thread { + + int priority; + int messageCount; + ActiveMQDestination dest; + + public ProducerThread(ActiveMQDestination dest, int messageCount, int priority) { + this.messageCount = messageCount; + this.priority = priority; + this.dest = dest; + } + + @Override + public void run() { + try { + MessageProducer producer = sess.createProducer(dest); + producer.setPriority(priority); + producer.setDeliveryMode(deliveryMode); + for (int i = 0; i < messageCount; i++) { + producer.send(sess.createTextMessage("message priority: " + priority)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void setMessagePriority(int priority) { + this.priority = priority; + } + + public void setMessageCount(int messageCount) { + this.messageCount = messageCount; + } + + } + + public void initCombosForTestQueues() { + addCombinationValues("useCache", new Object[] {new Boolean(true), new Boolean(false)}); + addCombinationValues("deliveryMode", new Object[] {new Integer(DeliveryMode.NON_PERSISTENT), new Integer(DeliveryMode.PERSISTENT)}); + } + + public void testQueues() throws Exception { + ActiveMQQueue queue = (ActiveMQQueue)sess.createQueue("TEST"); + + ProducerThread lowPri = new ProducerThread(queue, MSG_NUM, LOW_PRI); + ProducerThread highPri = new ProducerThread(queue, MSG_NUM, HIGH_PRI); + + lowPri.start(); + highPri.start(); + + lowPri.join(); + highPri.join(); + + MessageConsumer queueConsumer = sess.createConsumer(queue); + for (int i = 0; i < MSG_NUM * 2; i++) { + Message msg = queueConsumer.receive(5000); + LOG.debug("received i=" + i + ", " + (msg!=null? msg.getJMSMessageID() : null)); + assertNotNull("Message " + i + " was null", msg); + assertEquals("Message " + i + " has wrong priority", i < MSG_NUM ? HIGH_PRI : LOW_PRI, msg.getJMSPriority()); + } + } + + protected Message createMessage(int priority) throws Exception { + final String text = "priority " + priority; + Message msg = sess.createTextMessage(text); + LOG.info("Sending " + text); + return msg; + } + + public void initCombosForTestDurableSubs() { + addCombinationValues("prefetchVal", new Object[] {new Integer(1000), new Integer(MSG_NUM/4)}); + } + + public void testDurableSubs() throws Exception { + ActiveMQTopic topic = (ActiveMQTopic)sess.createTopic("TEST"); + TopicSubscriber sub = sess.createDurableSubscriber(topic, "priority"); + sub.close(); + + ProducerThread lowPri = new ProducerThread(topic, MSG_NUM, LOW_PRI); + ProducerThread highPri = new ProducerThread(topic, MSG_NUM, HIGH_PRI); + + lowPri.start(); + highPri.start(); + + lowPri.join(); + highPri.join(); + + sub = sess.createDurableSubscriber(topic, "priority"); + for (int i = 0; i < MSG_NUM * 2; i++) { + Message msg = sub.receive(5000); + assertNotNull("Message " + i + " was null", msg); + assertEquals("Message " + i + " has wrong priority", i < MSG_NUM ? HIGH_PRI : LOW_PRI, msg.getJMSPriority()); + } + + + // verify that same broker/store can deal with non priority dest also + topic = (ActiveMQTopic)sess.createTopic("HAS_NO_PRIORITY"); + sub = sess.createDurableSubscriber(topic, "no_priority"); + sub.close(); + + lowPri = new ProducerThread(topic, MSG_NUM, LOW_PRI); + highPri = new ProducerThread(topic, MSG_NUM, HIGH_PRI); + + lowPri.start(); + highPri.start(); + + lowPri.join(); + highPri.join(); + + sub = sess.createDurableSubscriber(topic, "no_priority"); + // verify we got them all + for (int i = 0; i < MSG_NUM * 2; i++) { + Message msg = sub.receive(5000); + assertNotNull("Message " + i + " was null", msg); + } + + } + + public void initCombosForTestDurableSubsReconnect() { + addCombinationValues("prefetchVal", new Object[] {new Integer(1000), new Integer(MSG_NUM/2)}); + // REVISIT = is dispatchAsync = true a problem or is it just the test? + addCombinationValues("dispatchAsync", new Object[] {Boolean.FALSE}); + addCombinationValues("useCache", new Object[] {Boolean.TRUE, Boolean.FALSE}); + } + + public void testDurableSubsReconnect() throws Exception { + ActiveMQTopic topic = (ActiveMQTopic)sess.createTopic("TEST"); + final String subName = "priorityDisconnect"; + TopicSubscriber sub = sess.createDurableSubscriber(topic, subName); + sub.close(); + + ProducerThread lowPri = new ProducerThread(topic, MSG_NUM, LOW_PRI); + ProducerThread highPri = new ProducerThread(topic, MSG_NUM, HIGH_PRI); + + lowPri.start(); + highPri.start(); + + lowPri.join(); + highPri.join(); + + + final int closeFrequency = MSG_NUM/4; + sub = sess.createDurableSubscriber(topic, subName); + for (int i = 0; i < MSG_NUM * 2; i++) { + Message msg = sub.receive(15000); + LOG.debug("received i=" + i + ", " + (msg!=null? msg.getJMSMessageID() : null)); + assertNotNull("Message " + i + " was null", msg); + assertEquals("Message " + i + " has wrong priority", i < MSG_NUM ? HIGH_PRI : LOW_PRI, msg.getJMSPriority()); + if (i>0 && i%closeFrequency==0) { + LOG.info("Closing durable sub.. on: " + i); + sub.close(); + sub = sess.createDurableSubscriber(topic, subName); + } + } + } + + public void testHighPriorityDelivery() throws Exception { + + // get zero prefetch + ActiveMQPrefetchPolicy prefetch = new ActiveMQPrefetchPolicy(); + prefetch.setAll(0); + factory.setPrefetchPolicy(prefetch); + conn.close(); + conn = factory.createConnection(); + conn.setClientID("priority"); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQTopic topic = (ActiveMQTopic)sess.createTopic("TEST"); + final String subName = "priorityDisconnect"; + TopicSubscriber sub = sess.createDurableSubscriber(topic, subName); + sub.close(); + + final int numToProduce = 2000; + final int[] dups = new int[numToProduce*2]; + ProducerThread producerThread = new ProducerThread(topic, numToProduce, LOW_PRI+1); + producerThread.run(); + LOG.info("Low priority messages sent"); + + sub = sess.createDurableSubscriber(topic, subName); + final int batchSize = 250; + int lowLowCount = 0; + for (int i=0; i exceptions = new Vector(); + BrokerService brokerService; + + protected BrokerService createBroker(PersistenceAdapter kaha) throws Exception { + + BrokerService broker = new BrokerService(); + broker.setUseJmx(false); + broker.setPersistenceAdapter(kaha); + return broker; + } + + protected PersistenceAdapter createStore(boolean delete) throws IOException { + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setJournalMaxFileLength(maxFileLength); + kaha.setCleanupInterval(5000); + if (delete) { + kaha.deleteAllMessages(); + } + return kaha; + } + + @Before + public void prepareCleanBrokerWithMultiStore() throws Exception { + prepareBrokerWithMultiStore(true); + } + + public void prepareBrokerWithMultiStore(boolean deleteAllMessages) throws Exception { + + MultiKahaDBPersistenceAdapter multiKahaDBPersistenceAdapter = new MultiKahaDBPersistenceAdapter(); + if (deleteAllMessages) { + multiKahaDBPersistenceAdapter.deleteAllMessages(); + } + ArrayList adapters = new ArrayList(); + + FilteredKahaDBPersistenceAdapter theRest = new FilteredKahaDBPersistenceAdapter(); + theRest.setPersistenceAdapter(createStore(deleteAllMessages)); + // default destination when not set is a match for all + adapters.add(theRest); + + // separate store for FastQ + FilteredKahaDBPersistenceAdapter fastQStore = new FilteredKahaDBPersistenceAdapter(); + fastQStore.setPersistenceAdapter(createStore(deleteAllMessages)); + fastQStore.setDestination(new ActiveMQQueue("FastQ")); + adapters.add(fastQStore); + + multiKahaDBPersistenceAdapter.setFilteredPersistenceAdapters(adapters); + brokerService = createBroker(multiKahaDBPersistenceAdapter); + } + + @After + public void tearDown() throws Exception { + brokerService.stop(); + } + + @Test + public void testTransactedSendReceive() throws Exception { + brokerService.start(); + sendMessages(true, "SlowQ", 1, 0); + assertEquals("got one", 1, receiveMessages(true, "SlowQ", 1)); + } + + @Test + public void testTransactedSendReceiveAcrossStores() throws Exception { + brokerService.start(); + sendMessages(true, "SlowQ,FastQ", 1, 0); + assertEquals("got one", 2, receiveMessages(true, "SlowQ,FastQ", 2)); + } + + @Test + public void testCommitRecovery() throws Exception { + doTestRecovery(true); + } + + @Test + public void testRollbackRecovery() throws Exception { + doTestRecovery(false); + } + + public void doTestRecovery(final boolean haveOutcome) throws Exception { + final MultiKahaDBPersistenceAdapter persistenceAdapter = + (MultiKahaDBPersistenceAdapter) brokerService.getPersistenceAdapter(); + MultiKahaDBTransactionStore transactionStore = + new MultiKahaDBTransactionStore(persistenceAdapter) { + @Override + public void persistOutcome(Tx tx, TransactionId txid) throws IOException { + if (haveOutcome) { + super.persistOutcome(tx, txid); + } + try { + // IOExceptions will stop the broker + persistenceAdapter.stop(); + } catch (Exception e) { + LOG.error("ex on stop ", e); + exceptions.add(e); + } + } + }; + persistenceAdapter.setTransactionStore(transactionStore); + brokerService.start(); + + ExecutorService executorService = Executors.newCachedThreadPool(); + executorService.execute(new Runnable() { + @Override + public void run() { + try { + // commit will block + sendMessages(true, "SlowQ,FastQ", 1, 0); + } catch(Exception expected) { + LOG.info("expected", expected); + } + } + }); + + brokerService.waitUntilStopped(); + // interrupt the send thread + executorService.shutdownNow(); + + // verify auto recovery + prepareBrokerWithMultiStore(false); + brokerService.start(); + + assertEquals("expect to get the recovered message", haveOutcome ? 2 : 0, receiveMessages(false, "SlowQ,FastQ", 2)); + assertEquals("all transactions are complete", 0, brokerService.getBroker().getPreparedTransactions(null).length); + } + + @Test + public void testDirectoryDefault() throws Exception { + MultiKahaDBPersistenceAdapter multiKahaDBPersistenceAdapter = new MultiKahaDBPersistenceAdapter(); + ArrayList adapters = new ArrayList(); + + FilteredKahaDBPersistenceAdapter otherFilteredKahaDBPersistenceAdapter = + new FilteredKahaDBPersistenceAdapter(); + PersistenceAdapter otherStore = createStore(false); + File someOtherDisk = new File("target" + File.separator + "someOtherDisk"); + otherStore.setDirectory(someOtherDisk); + otherFilteredKahaDBPersistenceAdapter.setPersistenceAdapter(otherStore); + otherFilteredKahaDBPersistenceAdapter.setDestination(new ActiveMQQueue("Other")); + adapters.add(otherFilteredKahaDBPersistenceAdapter); + + FilteredKahaDBPersistenceAdapter filteredKahaDBPersistenceAdapterDefault = + new FilteredKahaDBPersistenceAdapter(); + PersistenceAdapter storeDefault = createStore(false); + filteredKahaDBPersistenceAdapterDefault.setPersistenceAdapter(storeDefault); + adapters.add(filteredKahaDBPersistenceAdapterDefault); + + multiKahaDBPersistenceAdapter.setFilteredPersistenceAdapters(adapters); + + assertEquals(multiKahaDBPersistenceAdapter.getDirectory(), storeDefault.getDirectory().getParentFile()); + assertEquals(someOtherDisk, otherStore.getDirectory().getParentFile()); + } + + @Test + public void testSlowFastDestinationsStoreUsage() throws Exception { + brokerService.start(); + ExecutorService executorService = Executors.newCachedThreadPool(); + executorService.execute(new Runnable() { + @Override + public void run() { + try { + sendMessages(false, "SlowQ", 50, 500); + } catch (Exception e) { + exceptions.add(e); + } + } + }); + + executorService.execute(new Runnable() { + @Override + public void run() { + try { + sendMessages(false, "FastQ", numToSend, 0); + } catch (Exception e) { + exceptions.add(e); + } + } + }); + + executorService.execute(new Runnable() { + @Override + public void run() { + try { + assertEquals("Got all sent", numToSend, receiveMessages(false, "FastQ", numToSend)); + } catch (Exception e) { + exceptions.add(e); + } + } + }); + + executorService.shutdown(); + assertTrue("consumers executor finished on time", executorService.awaitTermination(5*60, TimeUnit.SECONDS)); + final SystemUsage usage = brokerService.getSystemUsage(); + assertTrue("Store is not hogged", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + long storeUsage = usage.getStoreUsage().getUsage(); + LOG.info("Store Usage: " + storeUsage); + return storeUsage < 5 * maxFileLength; + } + })); + assertTrue("no exceptions", exceptions.isEmpty()); + } + + private void sendMessages(boolean transacted, String destName, int count, long sleep) throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + try { + Session session = transacted ? connection.createSession(true, Session.SESSION_TRANSACTED) : connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(new ActiveMQQueue(destName)); + for (int i = 0; i < count; i++) { + if (sleep > 0) { + TimeUnit.MILLISECONDS.sleep(sleep); + } + producer.send(session.createTextMessage(createContent(i))); + } + if (transacted) { + session.commit(); + } + } finally { + connection.close(); + } + } + + private int receiveMessages(boolean transacted, String destName, int max) throws JMSException { + int rc = 0; + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + try { + connection.start(); + Session session = transacted ? connection.createSession(true, Session.SESSION_TRANSACTED) : connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer messageConsumer = session.createConsumer(new ActiveMQQueue(destName)); + while (rc < max && messageConsumer.receive(4000) != null) { + rc++; + + if (transacted && rc % 200 == 0) { + session.commit(); + } + } + if (transacted) { + session.commit(); + } + return rc; + } finally { + connection.close(); + } + } + + private String createContent(int i) { + StringBuilder sb = new StringBuilder(i + ":"); + while (sb.length() < 1024) { + sb.append("*"); + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/BrokenPersistenceAdapter.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/BrokenPersistenceAdapter.java new file mode 100644 index 0000000000..e275d75260 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/BrokenPersistenceAdapter.java @@ -0,0 +1,47 @@ +/** + * 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.store.jdbc; + +import java.io.IOException; + +import org.apache.activemq.broker.ConnectionContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class BrokenPersistenceAdapter extends JDBCPersistenceAdapter { + + private final Logger LOG = LoggerFactory.getLogger(BrokenPersistenceAdapter.class); + + private boolean shouldBreak = false; + + @Override + public void commitTransaction(ConnectionContext context) throws IOException { + if ( shouldBreak ) { + LOG.warn("Throwing exception on purpose"); + throw new IOException("Breaking on purpose"); + } + LOG.debug("in commitTransaction"); + super.commitTransaction(context); + } + + public void setShouldBreak(boolean shouldBreak) { + this.shouldBreak = shouldBreak; + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/DatabaseLockerConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/DatabaseLockerConfigTest.java new file mode 100644 index 0000000000..a99649dbbc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/DatabaseLockerConfigTest.java @@ -0,0 +1,55 @@ +/** + * 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.store.jdbc; + +import static org.junit.Assert.assertEquals; + +import org.apache.activemq.broker.AbstractLocker; +import org.junit.Test; + +public class DatabaseLockerConfigTest { + + @Test + public void testSleepConfig() throws Exception { + LeaseDatabaseLocker underTest = new LeaseDatabaseLocker(); + underTest.setLockAcquireSleepInterval(50); + underTest.configure(null); + assertEquals("configured sleep value retained", 50, underTest.getLockAcquireSleepInterval()); + } + + @Test + public void testDefaultSleepConfig() throws Exception { + LeaseDatabaseLocker underTest = new LeaseDatabaseLocker(); + underTest.configure(null); + assertEquals("configured sleep value retained", AbstractLocker.DEFAULT_LOCK_ACQUIRE_SLEEP_INTERVAL, underTest.getLockAcquireSleepInterval()); + } + + @Test + public void testSleepConfigOrig() throws Exception { + DefaultDatabaseLocker underTest = new DefaultDatabaseLocker(); + underTest.setLockAcquireSleepInterval(50); + underTest.configure(null); + assertEquals("configured sleep value retained", 50, underTest.getLockAcquireSleepInterval()); + } + + @Test + public void testDefaultSleepConfigOrig() throws Exception { + DefaultDatabaseLocker underTest = new DefaultDatabaseLocker(); + underTest.configure(null); + assertEquals("configured sleep value retained", AbstractLocker.DEFAULT_LOCK_ACQUIRE_SLEEP_INTERVAL, underTest.getLockAcquireSleepInterval()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCCommitExceptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCCommitExceptionTest.java new file mode 100644 index 0000000000..e183553642 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCCommitExceptionTest.java @@ -0,0 +1,175 @@ +/** + * 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.store.jdbc; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.wireformat.WireFormat; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// https://issues.apache.org/activemq/browse/AMQ-2880 +public class JDBCCommitExceptionTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(JDBCCommitExceptionTest.class); + + protected static final int messagesExpected = 10; + protected ActiveMQConnectionFactory factory; + protected BrokerService broker; + protected String connectionUri; + protected EmbeddedDataSource dataSource; + protected java.sql.Connection dbConnection; + protected BrokenPersistenceAdapter jdbc; + + @Override + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + + factory = new ActiveMQConnectionFactory( + connectionUri + "?jms.prefetchPolicy.all=0&jms.redeliveryPolicy.maximumRedeliveries="+messagesExpected); + } + + @Override + public void tearDown() throws Exception { + broker.stop(); + } + + public void testSqlException() throws Exception { + doTestSqlException(); + } + + public void doTestSqlException() throws Exception { + sendMessages(messagesExpected); + int messagesReceived = receiveMessages(messagesExpected); + + dumpMessages(); + assertEquals("Messages expected doesn't equal messages received", messagesExpected, messagesReceived); + broker.stop(); + } + + protected void dumpMessages() throws Exception { + WireFormat wireFormat = new OpenWireFormat(); + java.sql.Connection conn = ((JDBCPersistenceAdapter) broker.getPersistenceAdapter()).getDataSource().getConnection(); + PreparedStatement statement = conn.prepareStatement("SELECT ID, MSG FROM ACTIVEMQ_MSGS"); + ResultSet result = statement.executeQuery(); + LOG.info("Messages left in broker after test"); + while(result.next()) { + long id = result.getLong(1); + org.apache.activemq.command.Message message = (org.apache.activemq.command.Message)wireFormat.unmarshal(new ByteSequence(result.getBytes(2))); + LOG.info("id: " + id + ", message SeqId: " + message.getMessageId().getBrokerSequenceId() + ", MSG: " + message); + } + statement.close(); + conn.close(); + } + + protected int receiveMessages(int messagesExpected) throws Exception { + javax.jms.Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + + jdbc.setShouldBreak(true); + + // first try and receive these messages, they'll continually fail + receiveMessages(messagesExpected, session); + + jdbc.setShouldBreak(false); + + // now that the store is sane, try and get all the messages sent + return receiveMessages(messagesExpected, session); + } + + protected int receiveMessages(int messagesExpected, Session session) throws Exception { + int messagesReceived = 0; + + for (int i=0; i exceptions = new HashMap(); + + @Test + public void testShutdownWithoutTransportRestart() throws Exception { + + Mockery context = new Mockery() {{ + setImposteriser(ClassImposteriser.INSTANCE); + }}; + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + LOG.error("unexpected exception {} on thread {}", e, t); + exceptions.put(t, e); + } + }); + + final BrokerService brokerService = context.mock(BrokerService.class); + final JDBCPersistenceAdapter jdbcPersistenceAdapter = context.mock(JDBCPersistenceAdapter.class); + final Locker locker = context.mock(Locker.class); + + final States jdbcConn = context.states("jdbc").startsAs("down"); + final States broker = context.states("broker").startsAs("started"); + + // simulate jdbc up between hasLock and checkpoint, so hasLock fails to verify + context.checking(new Expectations() {{ + allowing(brokerService).isRestartAllowed(); + will(returnValue(false)); + allowing(brokerService).stopAllConnectors(with(any(ServiceStopper.class))); + allowing(brokerService).getPersistenceAdapter(); + will(returnValue(jdbcPersistenceAdapter)); + allowing(jdbcPersistenceAdapter).getLocker(); + will(returnValue(locker)); + allowing(locker).keepAlive(); + when(jdbcConn.is("down")); + will(returnValue(true)); + allowing(locker).keepAlive(); + when(jdbcConn.is("up")); + will(returnValue(false)); + + allowing(jdbcPersistenceAdapter).checkpoint(with(true)); + then(jdbcConn.is("up")); + allowing(brokerService).stop(); + then(broker.is("stopped")); + + }}); + + LeaseLockerIOExceptionHandler underTest = new LeaseLockerIOExceptionHandler(); + underTest.setBrokerService(brokerService); + + try { + underTest.handle(new IOException()); + fail("except suppress reply ex"); + } catch (SuppressReplyException expected) { + } + + assertTrue("broker stopped state triggered", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("broker state {}", broker); + return broker.is("stopped").isActive(); + } + })); + context.assertIsSatisfied(); + + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCIOExceptionHandlerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCIOExceptionHandlerTest.java new file mode 100644 index 0000000000..df10d73e89 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCIOExceptionHandlerTest.java @@ -0,0 +1,321 @@ +/** + * 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.store.jdbc; + +import java.io.PrintWriter; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Connection; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.LeaseLockerIOExceptionHandler; +import org.apache.activemq.util.Wait; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test to see if the JDBCExceptionIOHandler will restart the transport connectors correctly after + * the underlying DB has been stopped and restarted + * + * see AMQ-4575 + */ +public class JDBCIOExceptionHandlerTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(JDBCIOExceptionHandlerTest.class); + private static final String TRANSPORT_URL = "tcp://0.0.0.0:0"; + + private static final String DATABASE_NAME = "DERBY_OVERRIDE"; + private ActiveMQConnectionFactory factory; + private ReconnectingEmbeddedDataSource dataSource; + private BrokerService broker; + + protected BrokerService createBroker(boolean withJMX) throws Exception { + return createBroker("localhost", withJMX, true, true); + } + + protected BrokerService createBroker(String name, boolean withJMX, boolean leaseLocker, boolean startStopConnectors) throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName(name); + + broker.setUseJmx(withJMX); + + EmbeddedDataSource embeddedDataSource = new EmbeddedDataSource(); + embeddedDataSource.setDatabaseName(DATABASE_NAME); + embeddedDataSource.setCreateDatabase("create"); + + // create a wrapper to EmbeddedDataSource to allow the connection be + // reestablished to derby db + dataSource = new ReconnectingEmbeddedDataSource(embeddedDataSource); + + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + jdbc.setDataSource(dataSource); + + jdbc.setLockKeepAlivePeriod(1000l); + if (leaseLocker) { + LeaseDatabaseLocker leaseDatabaseLocker = new LeaseDatabaseLocker(); + leaseDatabaseLocker.setHandleStartException(true); + leaseDatabaseLocker.setLockAcquireSleepInterval(2000l); + jdbc.setLocker(leaseDatabaseLocker); + } + + broker.setPersistenceAdapter(jdbc); + LeaseLockerIOExceptionHandler ioExceptionHandler = new LeaseLockerIOExceptionHandler(); + ioExceptionHandler.setResumeCheckSleepPeriod(1000l); + ioExceptionHandler.setStopStartConnectors(startStopConnectors); + broker.setIoExceptionHandler(ioExceptionHandler); + String connectionUri = broker.addConnector(TRANSPORT_URL).getPublishableConnectString(); + + factory = new ActiveMQConnectionFactory(connectionUri); + + return broker; + } + + /* + * run test without JMX enabled + */ + public void testRecoverWithOutJMX() throws Exception { + recoverFromDisconnectDB(false); + } + + /* + * run test with JMX enabled + */ + public void testRecoverWithJMX() throws Exception { + recoverFromDisconnectDB(true); + } + + public void testSlaveStoppedLease() throws Exception { + testSlaveStopped(true); + } + + public void testSlaveStoppedDefault() throws Exception { + testSlaveStopped(false); + } + + public void testSlaveStopped(final boolean lease) throws Exception { + final BrokerService master = createBroker("master", true, lease, false); + master.start(); + master.waitUntilStarted(); + + final AtomicReference slave = new AtomicReference(); + + Thread slaveThread = new Thread() { + public void run() { + try { + BrokerService broker = new BrokerService(); + broker.setBrokerName("slave"); + + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + jdbc.setDataSource(dataSource); + + jdbc.setLockKeepAlivePeriod(1000l); + + if (lease) { + LeaseDatabaseLocker leaseDatabaseLocker = new LeaseDatabaseLocker(); + leaseDatabaseLocker.setHandleStartException(true); + leaseDatabaseLocker.setLockAcquireSleepInterval(2000l); + jdbc.setLocker(leaseDatabaseLocker); + } + + broker.setPersistenceAdapter(jdbc); + LeaseLockerIOExceptionHandler ioExceptionHandler = new LeaseLockerIOExceptionHandler(); + ioExceptionHandler.setResumeCheckSleepPeriod(1000l); + ioExceptionHandler.setStopStartConnectors(false); + broker.setIoExceptionHandler(ioExceptionHandler); + slave.set(broker); + broker.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + slaveThread.start(); + + Thread.sleep(5000); + + dataSource.stopDB(); + + assertTrue("Master hasn't been stopped", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return master.isStopped(); + } + })); + + assertTrue("Slave hasn't been stopped", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return slave.get().isStopped(); + } + })); + + } + + public void recoverFromDisconnectDB(boolean withJMX) throws Exception { + try { + broker = createBroker(withJMX); + broker.start(); + broker.waitUntilStarted(); + + // broker started - stop db underneath it + dataSource.stopDB(); + + // wait - allow the leaselocker to kick the JDBCIOExceptionHandler + TimeUnit.SECONDS.sleep(3); + + // check connector has shutdown + checkTransportConnectorStopped(); + + // restart db underneath + dataSource.restartDB(); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.debug("*** checking connector to start..."); + try { + checkTransportConnectorStarted(); + return true; + } catch (Throwable t) { + LOG.debug(t.toString()); + } + return false; + } + }); + + + } finally { + LOG.debug("*** broker is stopping..."); + broker.stop(); + } + } + + private void checkTransportConnectorStopped() { + // connection is expected to fail + try { + factory.createConnection(); + fail("Transport connector should be stopped"); + } catch (Exception ex) { + // expected an exception + LOG.debug(" checkTransportConnectorStopped() threw", ex); + } + } + + private void checkTransportConnectorStarted() { + // connection is expected to succeed + try { + Connection conn = factory.createConnection(); + conn.close(); + } catch (Exception ex) { + LOG.debug("checkTransportConnectorStarted() threw", ex); + fail("Transport connector should have been started"); + } + } + + /* + * Wrapped the derby datasource object to get DB reconnect functionality as I not + * manage to get that working directly on the EmbeddedDataSource + * + * NOTE: Not a thread Safe but for this unit test it should be fine + */ + public class ReconnectingEmbeddedDataSource implements javax.sql.DataSource { + + private EmbeddedDataSource realDatasource; + + public ReconnectingEmbeddedDataSource(EmbeddedDataSource datasource) { + this.realDatasource = datasource; + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return this.realDatasource.getLogWriter(); + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + this.realDatasource.setLogWriter(out); + + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + this.realDatasource.setLoginTimeout(seconds); + } + + @Override + public int getLoginTimeout() throws SQLException { + return this.realDatasource.getLoginTimeout(); + } + + @Override + public T unwrap(Class iface) throws SQLException { + return this.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return this.isWrapperFor(iface); + } + + @Override + public java.sql.Connection getConnection() throws SQLException { + return this.realDatasource.getConnection(); + } + + @Override + public java.sql.Connection getConnection(String username, String password) throws SQLException { + return this.getConnection(username, password); + } + + /** + * + * To simulate a db reconnect I just create a new EmbeddedDataSource . + * + * @throws SQLException + */ + public void restartDB() throws SQLException { + EmbeddedDataSource newDatasource = new EmbeddedDataSource(); + newDatasource.setDatabaseName(DATABASE_NAME); + newDatasource.getConnection(); + LOG.info("*** DB restarted now..."); + this.realDatasource = newDatasource; + } + + public void stopDB() { + try { + realDatasource.setShutdownDatabase("shutdown"); + LOG.info("***DB is being shutdown..."); + dataSource.getConnection(); + fail("should have thrown a db closed exception"); + } catch (Exception ex) { + ex.printStackTrace(System.out); + } + } + + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCLockTablePrefix.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCLockTablePrefix.xml new file mode 100644 index 0000000000..ac70fa7f4b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCLockTablePrefix.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCLockTablePrefixTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCLockTablePrefixTest.java new file mode 100644 index 0000000000..e5b47ba015 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCLockTablePrefixTest.java @@ -0,0 +1,42 @@ +/** + * 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.store.jdbc; + +import junit.framework.TestCase; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; + +public class JDBCLockTablePrefixTest extends TestCase { + + public void testLockTable() throws Exception { + BrokerService broker = BrokerFactory.createBroker("xbean:org/apache/activemq/store/jdbc/JDBCLockTablePrefix.xml"); + broker.waitUntilStarted(); + + PersistenceAdapter pa = broker.getPersistenceAdapter(); + assertNotNull(pa); + + JDBCPersistenceAdapter jpa = (JDBCPersistenceAdapter) pa; + assertEquals("TTT_", jpa.getStatements().getTablePrefix()); + assertEquals("AMQ_MSGS2", jpa.getStatements().getMessageTableName()); + assertEquals("AMQ_LOCK2", jpa.getStatements().getLockTableName()); + + broker.stop(); + broker.waitUntilStopped(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCMessagePriorityTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCMessagePriorityTest.java new file mode 100644 index 0000000000..34796a4a3b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCMessagePriorityTest.java @@ -0,0 +1,453 @@ +/** + * 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.store.jdbc; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TopicSubscriber; + +import junit.framework.Test; + +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.MessagePriorityTest; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JDBCMessagePriorityTest extends MessagePriorityTest { + + private static final Logger LOG = LoggerFactory.getLogger(JDBCMessagePriorityTest.class); + EmbeddedDataSource dataSource; + JDBCPersistenceAdapter jdbc; + + @Override + protected PersistenceAdapter createPersistenceAdapter(boolean delete) throws Exception { + jdbc = new JDBCPersistenceAdapter(); + dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + dataSource.setShutdownDatabase(null); + jdbc.setDataSource(dataSource); + jdbc.deleteAllMessages(); + jdbc.setCleanupPeriod(2000); + return jdbc; + } + + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + try { + if (dataSource != null) { + // ref http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBCDataSource.java?view=markup + dataSource.setShutdownDatabase("shutdown"); + dataSource.getConnection(); + } + } catch (Exception ignored) { + } finally { + dataSource.setShutdownDatabase(null); + } + + } + + // this cannot be a general test as kahaDB just has support for 3 priority levels + public void testDurableSubsReconnectWithFourLevels() throws Exception { + ActiveMQTopic topic = (ActiveMQTopic) sess.createTopic("TEST"); + final String subName = "priorityDisconnect"; + TopicSubscriber sub = sess.createDurableSubscriber(topic, subName); + sub.close(); + + final int MED_PRI = LOW_PRI + 1; + final int MED_HIGH_PRI = HIGH_PRI - 1; + + ProducerThread lowPri = new ProducerThread(topic, MSG_NUM, LOW_PRI); + ProducerThread medPri = new ProducerThread(topic, MSG_NUM, MED_PRI); + ProducerThread medHighPri = new ProducerThread(topic, MSG_NUM, MED_HIGH_PRI); + ProducerThread highPri = new ProducerThread(topic, MSG_NUM, HIGH_PRI); + + lowPri.start(); + highPri.start(); + medPri.start(); + medHighPri.start(); + + lowPri.join(); + highPri.join(); + medPri.join(); + medHighPri.join(); + + + final int closeFrequency = MSG_NUM; + final int[] priorities = new int[]{HIGH_PRI, MED_HIGH_PRI, MED_PRI, LOW_PRI}; + sub = sess.createDurableSubscriber(topic, subName); + for (int i = 0; i < MSG_NUM * 4; i++) { + Message msg = sub.receive(10000); + LOG.debug("received i=" + i + ", m=" + (msg != null ? + msg.getJMSMessageID() + ", priority: " + msg.getJMSPriority() + : null)); + assertNotNull("Message " + i + " was null", msg); + assertEquals("Message " + i + " has wrong priority", priorities[i / MSG_NUM], msg.getJMSPriority()); + if (i > 0 && i % closeFrequency == 0) { + LOG.info("Closing durable sub.. on: " + i); + sub.close(); + sub = sess.createDurableSubscriber(topic, subName); + } + } + LOG.info("closing on done!"); + sub.close(); + } + + public void initCombosForTestConcurrentDurableSubsReconnectWithXLevels() { + addCombinationValues("prioritizeMessages", new Object[]{Boolean.TRUE, Boolean.FALSE}); + } + + public void testConcurrentDurableSubsReconnectWithXLevels() throws Exception { + ActiveMQTopic topic = (ActiveMQTopic) sess.createTopic("TEST"); + final String subName = "priorityDisconnect"; + Connection consumerConn = factory.createConnection(); + consumerConn.setClientID("priorityDisconnect"); + consumerConn.start(); + Session consumerSession = consumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + TopicSubscriber sub = consumerSession.createDurableSubscriber(topic, subName); + sub.close(); + + final int maxPriority = 5; + + final AtomicInteger[] messageCounts = new AtomicInteger[maxPriority]; + final long[] messageIds = new long[maxPriority]; + Vector producers = new Vector(); + for (int priority = 0; priority < maxPriority; priority++) { + producers.add(new ProducerThread(topic, MSG_NUM, priority)); + messageCounts[priority] = new AtomicInteger(0); + messageIds[priority] = 1l; + } + + for (ProducerThread producer : producers) { + producer.start(); + } + + final int closeFrequency = MSG_NUM / 2; + HashMap dups = new HashMap(); + sub = consumerSession.createDurableSubscriber(topic, subName); + for (int i = 0; i < MSG_NUM * maxPriority; i++) { + Message msg = sub.receive(10000); + LOG.debug("received i=" + i + ", m=" + (msg != null ? + msg.getJMSMessageID() + ", priority: " + msg.getJMSPriority() + : null)); + assertNotNull("Message " + i + " was null, counts: " + Arrays.toString(messageCounts), msg); + assertNull("no duplicate message failed on : " + msg.getJMSMessageID(), dups.put(msg.getJMSMessageID(), subName)); + messageCounts[msg.getJMSPriority()].incrementAndGet(); + assertEquals("message is in order : " + msg, + messageIds[msg.getJMSPriority()],((ActiveMQMessage)msg).getMessageId().getProducerSequenceId()); + messageIds[msg.getJMSPriority()]++; + if (i > 0 && i % closeFrequency == 0) { + LOG.info("Closing durable sub.. on: " + i + ", counts: " + Arrays.toString(messageCounts)); + sub.close(); + sub = consumerSession.createDurableSubscriber(topic, subName); + } + } + LOG.info("closing on done!"); + sub.close(); + consumerSession.close(); + consumerConn.close(); + + for (ProducerThread producer : producers) { + producer.join(); + } + } + + public void initCombosForTestConcurrentRate() { + addCombinationValues("prefetchVal", new Object[]{new Integer(1), new Integer(500)}); + } + + public void testConcurrentRate() throws Exception { + ActiveMQTopic topic = (ActiveMQTopic) sess.createTopic("TEST"); + final String subName = "priorityConcurrent"; + Connection consumerConn = factory.createConnection(); + consumerConn.setClientID("subName"); + consumerConn.start(); + Session consumerSession = consumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = consumerSession.createDurableSubscriber(topic, subName); + sub.close(); + + final int TO_SEND = 2000; + final Vector duplicates = new Vector(); + final int[] dups = new int[TO_SEND * 4]; + long start; + double max = 0, sum = 0; + MessageProducer messageProducer = sess.createProducer(topic); + TextMessage message = sess.createTextMessage(); + for (int i = 0; i < TO_SEND; i++) { + int priority = i % 10; + message.setText(i + "-" + priority); + message.setIntProperty("seq", i); + message.setJMSPriority(priority); + if (i > 0 && i % 1000 == 0) { + LOG.info("Max send time: " + max + ". Sending message: " + message.getText()); + } + start = System.currentTimeMillis(); + messageProducer.send(message, DeliveryMode.PERSISTENT, message.getJMSPriority(), 0); + long duration = System.currentTimeMillis() - start; + max = Math.max(max, duration); + if (duration == max) { + LOG.info("new max: " + max + " on i=" + i + ", " + message.getText()); + } + sum += duration; + } + + LOG.info("Sent: " + TO_SEND + ", max send time: " + max); + + double noConsumerAve = (sum * 100 / TO_SEND); + sub = consumerSession.createDurableSubscriber(topic, subName); + final AtomicInteger count = new AtomicInteger(); + sub.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + count.incrementAndGet(); + if (count.get() % 100 == 0) { + LOG.info("onMessage: count: " + count.get() + ", " + ((TextMessage) message).getText() + ", seqNo " + message.getIntProperty("seq") + ", " + message.getJMSMessageID()); + } + int seqNo = message.getIntProperty("seq"); + if (dups[seqNo] == 0) { + dups[seqNo] = 1; + } else { + LOG.error("Duplicate: " + ((TextMessage) message).getText() + ", " + message.getJMSMessageID()); + duplicates.add(message); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + LOG.info("Activated consumer"); + sum = max = 0; + for (int i = TO_SEND; i < (TO_SEND * 2); i++) { + int priority = i % 10; + message.setText(i + "-" + priority); + message.setIntProperty("seq", i); + message.setJMSPriority(priority); + if (i > 0 && i % 1000 == 0) { + LOG.info("Max send time: " + max + ". Sending message: " + message.getText()); + } + start = System.currentTimeMillis(); + messageProducer.send(message, DeliveryMode.PERSISTENT, message.getJMSPriority(), 0); + long duration = System.currentTimeMillis() - start; + max = Math.max(max, duration); + if (duration == max) { + LOG.info("new max: " + max + " on i=" + i + ", " + message.getText()); + } + sum += duration; + } + LOG.info("Sent another: " + TO_SEND + ", max send time: " + max); + + double withConsumerAve = (sum * 100 / TO_SEND); + final int reasonableMultiplier = 4; // not so reasonable, but on slow disks it can be + assertTrue("max X times as slow with consumer:" + withConsumerAve + " , noConsumerMax:" + noConsumerAve, + withConsumerAve < noConsumerAve * reasonableMultiplier); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("count: " + count.get()); + return TO_SEND * 2 == count.get(); + } + }, 60 * 1000); + + assertTrue("No duplicates : " + duplicates, duplicates.isEmpty()); + assertEquals("got all messages", TO_SEND * 2, count.get()); + } + + public void testCleanupPriorityDestination() throws Exception { + assertEquals("no messages pending", 0, messageTableCount()); + + ActiveMQTopic topic = (ActiveMQTopic) sess.createTopic("TEST"); + final String subName = "priorityConcurrent"; + Connection consumerConn = factory.createConnection(); + consumerConn.setClientID("subName"); + consumerConn.start(); + Session consumerSession = consumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = consumerSession.createDurableSubscriber(topic, subName); + sub.close(); + + MessageProducer messageProducer = sess.createProducer(topic); + Message message = sess.createTextMessage(); + message.setJMSPriority(2); + messageProducer.send(message, DeliveryMode.PERSISTENT, message.getJMSPriority(), 0); + message.setJMSPriority(5); + messageProducer.send(message, DeliveryMode.PERSISTENT, message.getJMSPriority(), 0); + + assertEquals("two messages pending", 2, messageTableCount()); + + sub = consumerSession.createDurableSubscriber(topic, subName); + + message = sub.receive(5000); + assertEquals("got high priority", 5, message.getJMSPriority()); + + waitForAck(5); + + for (int i=0; i<10; i++) { + jdbc.cleanup(); + } + assertEquals("one messages pending", 1, messageTableCount()); + + message = sub.receive(5000); + assertEquals("got high priority", 2, message.getJMSPriority()); + + waitForAck(2); + + for (int i=0; i<10; i++) { + jdbc.cleanup(); + } + assertEquals("no messages pending", 0, messageTableCount()); + } + + + public void testCleanupNonPriorityDestination() throws Exception { + assertEquals("no messages pending", 0, messageTableCount()); + + ActiveMQTopic topic = (ActiveMQTopic) sess.createTopic("TEST_CLEANUP_NO_PRIORITY"); + final String subName = "subName"; + Connection consumerConn = factory.createConnection(); + consumerConn.setClientID("subName"); + consumerConn.start(); + Session consumerSession = consumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = consumerSession.createDurableSubscriber(topic, subName); + sub.close(); + + MessageProducer messageProducer = sess.createProducer(topic); + Message message = sess.createTextMessage("ToExpire"); + messageProducer.send(message, DeliveryMode.PERSISTENT, Message.DEFAULT_PRIORITY, 4000); + + message = sess.createTextMessage("A"); + messageProducer.send(message); + message = sess.createTextMessage("B"); + messageProducer.send(message); + message = null; + + assertEquals("three messages pending", 3, messageTableCount()); + + // let first message expire + TimeUnit.SECONDS.sleep(5); + + sub = consumerSession.createDurableSubscriber(topic, subName); + message = sub.receive(5000); + assertNotNull("got message", message); + LOG.info("Got: " + message); + + waitForAck(0, 1); + + for (int i=0; i<10; i++) { + jdbc.cleanup(); + } + assertEquals("one messages pending", 1, messageTableCount()); + + message = sub.receive(5000); + assertNotNull("got message two", message); + LOG.info("Got: " + message); + + waitForAck(0, 2); + + for (int i=0; i<10; i++) { + jdbc.cleanup(); + } + assertEquals("no messages pending", 0, messageTableCount()); + } + + private int messageTableCount() throws Exception { + int count = -1; + java.sql.Connection c = dataSource.getConnection(); + try { + PreparedStatement s = c.prepareStatement("SELECT COUNT(*) FROM ACTIVEMQ_MSGS"); + ResultSet rs = s.executeQuery(); + if (rs.next()) { + count = rs.getInt(1); + } + } finally { + if (c!=null) { + c.close(); + } + } + return count; + } + + private void waitForAck(final int priority) throws Exception { + waitForAck(priority, 0); + } + + private void waitForAck(final int priority, final int minId) throws Exception { + assertTrue("got ack for " + priority, Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + int id = 0; + java.sql.Connection c = dataSource.getConnection(); + try { + PreparedStatement s = c.prepareStatement("SELECT LAST_ACKED_ID FROM ACTIVEMQ_ACKS WHERE PRIORITY=" + priority); + ResultSet rs = s.executeQuery(); + if (rs.next()) { + id = rs.getInt(1); + } + } finally { + if (c!=null) { + c.close(); + } + } + return id>minId; + } + })); + } + + @SuppressWarnings("unused") + private int messageTableDump() throws Exception { + int count = -1; + java.sql.Connection c = dataSource.getConnection(); + try { + PreparedStatement s = c.prepareStatement("SELECT * FROM ACTIVEMQ_MSGS"); + ResultSet rs = s.executeQuery(); + if (rs.next()) { + count = rs.getInt(1); + } + } finally { + if (c!=null) { + c.close(); + } + } + return count; + } + + public static Test suite() { + return suite(JDBCMessagePriorityTest.class); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCNegativeQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCNegativeQueueTest.java new file mode 100644 index 0000000000..998ff7c5d7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCNegativeQueueTest.java @@ -0,0 +1,91 @@ +/** + * 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.store.jdbc; + +import java.io.PrintStream; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.cursors.NegativeQueueTest; +import org.apache.derby.jdbc.EmbeddedDataSource; + +public class JDBCNegativeQueueTest extends NegativeQueueTest { + + EmbeddedDataSource dataSource; + + protected void configureBroker(BrokerService answer) throws Exception { + super.configureBroker(answer); + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + answer.setPersistenceAdapter(jdbc); + } + + protected void tearDown() throws Exception { + if (DEBUG) { + printQuery("Select * from ACTIVEMQ_MSGS", System.out); + } + super.tearDown(); + } + + + private void printQuery(String query, PrintStream out) + throws SQLException { + Connection conn = dataSource.getConnection(); + printQuery(conn.prepareStatement(query), out); + conn.close(); + } + + private void printQuery(PreparedStatement s, PrintStream out) + throws SQLException { + + ResultSet set = null; + try { + set = s.executeQuery(); + ResultSetMetaData metaData = set.getMetaData(); + for (int i = 1; i <= metaData.getColumnCount(); i++) { + if (i == 1) + out.print("||"); + out.print(metaData.getColumnName(i) + "||"); + } + out.println(); + while (set.next()) { + for (int i = 1; i <= metaData.getColumnCount(); i++) { + if (i == 1) + out.print("|"); + out.print(set.getString(i) + "|"); + } + out.println(); + } + } finally { + try { + set.close(); + } catch (Throwable ignore) { + } + try { + s.close(); + } catch (Throwable ignore) { + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCNetworkBrokerDetachTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCNetworkBrokerDetachTest.java new file mode 100644 index 0000000000..409b20f0eb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCNetworkBrokerDetachTest.java @@ -0,0 +1,36 @@ +/** + * 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.store.jdbc; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.network.NetworkBrokerDetachTest; +import org.apache.derby.jdbc.EmbeddedDataSource; + +public class JDBCNetworkBrokerDetachTest extends NetworkBrokerDetachTest { + + protected void configureBroker(BrokerService broker) throws Exception { + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName(broker.getBrokerName()); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + jdbc.deleteAllMessages(); + broker.setPersistenceAdapter(jdbc); + broker.setUseVirtualTopics(false); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCPersistenceAdapterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCPersistenceAdapterTest.java new file mode 100644 index 0000000000..ce539d2381 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCPersistenceAdapterTest.java @@ -0,0 +1,65 @@ +/** + * 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.store.jdbc; + +import java.io.IOException; + +import junit.framework.AssertionFailedError; + +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.PersistenceAdapterTestSupport; +import org.apache.derby.jdbc.EmbeddedDataSource; + +public class JDBCPersistenceAdapterTest extends PersistenceAdapterTestSupport { + + protected PersistenceAdapter createPersistenceAdapter(boolean delete) throws IOException { + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + + // explicitly enable audit as it is now off by default + // due to org.apache.activemq.broker.ProducerBrokerExchange.canDispatch(Message) + jdbc.setEnableAudit(true); + + brokerService.setSchedulerSupport(false); + brokerService.setPersistenceAdapter(jdbc); + jdbc.setBrokerService(brokerService); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + if( delete ) { + jdbc.deleteAllMessages(); + } + return jdbc; + } + + public void testAuditOff() throws Exception { + pa.stop(); + pa = createPersistenceAdapter(true); + ((JDBCPersistenceAdapter)pa).setEnableAudit(false); + pa.start(); + boolean failed = true; + try { + testStoreCanHandleDupMessages(); + failed = false; + } catch (AssertionFailedError e) { + } + + if (!failed) { + fail("Should have failed with audit turned off"); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreAutoCommitTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreAutoCommitTest.java new file mode 100644 index 0000000000..b9e6e98bdd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreAutoCommitTest.java @@ -0,0 +1,502 @@ +/** + * 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.store.jdbc; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URI; +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.junit.Test; + +/** + * to be compliant with JDBC spec; officially commit is not supposed to be + * called on a connection that uses autocommit.The oracle v12 driver does a + * check for autocommitSpecCompliance and it causes issues + *

+ * To test; wrap the datasource used by the broker and check for autocommit + * before delegating to real datasource. If commit is called on connection with + * autocommit, wrapper throws a SQLException. + */ + +public class JDBCStoreAutoCommitTest { + + private static final String BROKER_NAME = "AutoCommitTest"; + private static final String TEST_DEST = "commitCheck"; + private static final String MSG_TEXT = "JDBCStoreAutoCommitTest TEST"; + + /** + * verify dropping and recreating tables + * + * @throws Exception + */ + @Test + public void testDeleteAllMessages() throws Exception { + BrokerService broker = createBrokerService(); + broker.getPersistenceAdapter().deleteAllMessages(); + broker.setUseJmx(false); + broker.start(); + broker.waitUntilStarted(); + broker.stop(); + broker.waitUntilStopped(); + } + + /** + * Send message and consume message, JMS session is not transacted + * + * @throws Exception + */ + @Test + public void testSendConsume() throws Exception { + this.doSendConsume(false); + } + + /** + * send message and consume message, JMS session is transacted + * + * @throws Exception + */ + @Test + public void testSendConsumeTransacted() throws Exception { + this.doSendConsume(true); + } + + private void doSendConsume(boolean transacted) throws Exception { + + BrokerService broker = createBrokerService(); + broker.setUseJmx(false); + broker.start(); + broker.waitUntilStarted(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(new URI("vm:" + BROKER_NAME)); + ActiveMQConnection c1 = (ActiveMQConnection) cf.createConnection(); + c1.start(); + + try { + // message send + Session session1 = c1.createSession(transacted, Session.AUTO_ACKNOWLEDGE); + MessageProducer messageProducer = session1.createProducer(session1.createQueue(TEST_DEST)); + TextMessage textMessage = session1.createTextMessage(MSG_TEXT); + messageProducer.send(textMessage); + + if (transacted) { + session1.commit(); + } + + // consume + Session session2 = c1.createSession(transacted, Session.AUTO_ACKNOWLEDGE); + MessageConsumer messageConsumer = session2.createConsumer(session2.createQueue(TEST_DEST)); + TextMessage messageReceived = (TextMessage) messageConsumer.receive(1000); + + assertEquals("check message received", MSG_TEXT, messageReceived.getText()); + } finally { + c1.close(); + broker.stop(); + broker.waitUntilStopped(); + } + } + + private BrokerService createBrokerService() throws IOException { + BrokerService broker = new BrokerService(); + broker.setBrokerName(BROKER_NAME); + broker.setUseJmx(false); + + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource embeddedDataSource = new EmbeddedDataSource(); + embeddedDataSource.setDatabaseName("derbyDb"); + embeddedDataSource.setCreateDatabase("create"); + + javax.sql.DataSource wrappedDataSource = new TestDataSource(embeddedDataSource); + + jdbc.setDataSource(wrappedDataSource); + + broker.setPersistenceAdapter(jdbc); + return broker; + } + + private class TestDataSource implements javax.sql.DataSource { + + private final javax.sql.DataSource realDataSource; + + public TestDataSource(javax.sql.DataSource dataSource) { + realDataSource = dataSource; + } + + @Override + public Connection getConnection() throws SQLException { + Connection autoCommitCheckConnection = new AutoCommitCheckConnection(realDataSource.getConnection()); + return autoCommitCheckConnection; + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + Connection autoCommitCheckConnection = new AutoCommitCheckConnection(realDataSource.getConnection(username, password)); + + return autoCommitCheckConnection; + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return realDataSource.getLogWriter(); + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + realDataSource.setLogWriter(out); + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + realDataSource.setLoginTimeout(seconds); + } + + @Override + public int getLoginTimeout() throws SQLException { + return realDataSource.getLoginTimeout(); + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return realDataSource.getParentLogger(); + } + + @Override + public T unwrap(Class iface) throws SQLException { + return realDataSource.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return realDataSource.isWrapperFor(iface); + } + } + + private class AutoCommitCheckConnection implements Connection { + + private final Connection realConnection; + + public AutoCommitCheckConnection(Connection connection) { + this.realConnection = connection; + } + + // verify commit is not called on an auto-commit connection + @Override + public void commit() throws SQLException { + if (getAutoCommit() == true) { + throw new SQLException("AutoCommitCheckConnection: Called commit on autoCommit Connection"); + } + realConnection.commit(); + } + + // Just plumbing for wrapper. Might have been better to do a Dynamic Proxy here. + + @Override + public Statement createStatement() throws SQLException { + return realConnection.createStatement(); + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + return realConnection.prepareStatement(sql); + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + return realConnection.prepareCall(sql); + } + + @Override + public String nativeSQL(String sql) throws SQLException { + return realConnection.nativeSQL(sql); + } + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + realConnection.setAutoCommit(autoCommit); + } + + @Override + public boolean getAutoCommit() throws SQLException { + return realConnection.getAutoCommit(); + } + + @Override + public void rollback() throws SQLException { + realConnection.rollback(); + } + + @Override + public void close() throws SQLException { + realConnection.close(); + } + + @Override + public boolean isClosed() throws SQLException { + return realConnection.isClosed(); + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return realConnection.getMetaData(); + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + realConnection.setReadOnly(readOnly); + } + + @Override + public boolean isReadOnly() throws SQLException { + return realConnection.isReadOnly(); + } + + @Override + public void setCatalog(String catalog) throws SQLException { + realConnection.setCatalog(catalog); + } + + @Override + public String getCatalog() throws SQLException { + return realConnection.getCatalog(); + } + + @Override + public void setTransactionIsolation(int level) throws SQLException { + realConnection.setTransactionIsolation(level); + } + + @Override + public int getTransactionIsolation() throws SQLException { + return realConnection.getTransactionIsolation(); + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return realConnection.getWarnings(); + } + + @Override + public void clearWarnings() throws SQLException { + realConnection.clearWarnings(); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return realConnection.createStatement(resultSetType, resultSetConcurrency); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return realConnection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + @Override + public Map> getTypeMap() throws SQLException { + return realConnection.getTypeMap(); + } + + @Override + public void setTypeMap(Map> map) throws SQLException { + realConnection.setTypeMap(map); + } + + @Override + public void setHoldability(int holdability) throws SQLException { + realConnection.setHoldability(holdability); + } + + @Override + public int getHoldability() throws SQLException { + return realConnection.getHoldability(); + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return realConnection.setSavepoint(); + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + return realConnection.setSavepoint(name); + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + realConnection.rollback(); + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + realConnection.releaseSavepoint(savepoint); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return realConnection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return realConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return realConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + return realConnection.prepareStatement(sql, autoGeneratedKeys); + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + return realConnection.prepareStatement(sql, columnIndexes); + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + return realConnection.prepareStatement(sql, columnNames); + } + + @Override + public Clob createClob() throws SQLException { + return realConnection.createClob(); + } + + @Override + public Blob createBlob() throws SQLException { + return realConnection.createBlob(); + } + + @Override + public NClob createNClob() throws SQLException { + return realConnection.createNClob(); + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return realConnection.createSQLXML(); + } + + @Override + public boolean isValid(int timeout) throws SQLException { + return realConnection.isValid(timeout); + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + realConnection.setClientInfo(name, value); + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + realConnection.setClientInfo(properties); + } + + @Override + public String getClientInfo(String name) throws SQLException { + return realConnection.getClientInfo(name); + } + + @Override + public Properties getClientInfo() throws SQLException { + return realConnection.getClientInfo(); + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return realConnection.createArrayOf(typeName, elements); + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return realConnection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + realConnection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return realConnection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + realConnection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + realConnection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return realConnection.getNetworkTimeout(); + } + + @Override + public T unwrap(Class iface) throws SQLException { + return realConnection.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return realConnection.isWrapperFor(iface); + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreBrokerTest.java new file mode 100644 index 0000000000..6e78927cd4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreBrokerTest.java @@ -0,0 +1,60 @@ +/** + * 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.store.jdbc; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTest; +import org.apache.derby.jdbc.EmbeddedDataSource; + +public class JDBCStoreBrokerTest extends BrokerTest { + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + + jdbc.deleteAllMessages(); + broker.setPersistenceAdapter(jdbc); + return broker; + } + + protected BrokerService createRestartedBroker() throws Exception { + BrokerService broker = new BrokerService(); + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + broker.setPersistenceAdapter(jdbc); + return broker; + } + + + public static Test suite() { + return suite(JDBCStoreBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreOrderTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreOrderTest.java new file mode 100644 index 0000000000..4d3ac55953 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCStoreOrderTest.java @@ -0,0 +1,63 @@ +/** + * 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.store.jdbc; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.Message; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.store.StoreOrderTest; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.wireformat.WireFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.derby.jdbc.EmbeddedDataSource; + +// https://issues.apache.org/activemq/browse/AMQ-2594 +public class JDBCStoreOrderTest extends StoreOrderTest { + + private static final Logger LOG = LoggerFactory.getLogger(JDBCStoreOrderTest.class); + + @Override + protected void dumpMessages() throws Exception { + WireFormat wireFormat = new OpenWireFormat(); + java.sql.Connection conn = ((JDBCPersistenceAdapter) broker.getPersistenceAdapter()).getDataSource().getConnection(); + PreparedStatement statement = conn.prepareStatement("SELECT ID, MSG FROM ACTIVEMQ_MSGS"); + ResultSet result = statement.executeQuery(); + while(result.next()) { + long id = result.getLong(1); + Message message = (Message)wireFormat.unmarshal(new ByteSequence(result.getBytes(2))); + LOG.info("id: " + id + ", message SeqId: " + message.getMessageId().getBrokerSequenceId() + ", MSG: " + message); + } + statement.close(); + conn.close(); + } + + @Override + protected void setPersistentAdapter(BrokerService brokerService) + throws Exception { + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + brokerService.setPersistenceAdapter(jdbc); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCTablePrefixAssignedTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCTablePrefixAssignedTest.java new file mode 100644 index 0000000000..06f623f25d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCTablePrefixAssignedTest.java @@ -0,0 +1,132 @@ +/** + * 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.store.jdbc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Destination; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.Message; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.store.jdbc.adapter.DefaultJDBCAdapter; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.wireformat.WireFormat; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JDBCTablePrefixAssignedTest { + + private static final Logger LOG = LoggerFactory.getLogger(JDBCTablePrefixAssignedTest.class); + + private BrokerService service; + + @Before + public void setUp() throws Exception { + service = createBroker(); + service.start(); + service.waitUntilStarted(); + } + + @After + public void tearDown() throws Exception { + service.stop(); + service.waitUntilStopped(); + } + + @Test + public void testTablesHave() throws Exception { + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?create=false"); + ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue("TEST.FOO"); + MessageProducer producer = session.createProducer(destination); + + for (int i = 0; i < 10; ++i) { + producer.send(session.createTextMessage("test")); + } + producer.close(); + connection.close(); + + List queuedMessages = null; + try { + queuedMessages = dumpMessages(); + } catch (Exception ex) { + LOG.info("Caught ex: ", ex); + fail("Should not have thrown an exception"); + } + + assertNotNull(queuedMessages); + assertEquals("Should have found 10 messages", 10, queuedMessages.size()); + } + + protected List dumpMessages() throws Exception { + WireFormat wireFormat = new OpenWireFormat(); + java.sql.Connection conn = ((JDBCPersistenceAdapter) service.getPersistenceAdapter()).getDataSource().getConnection(); + PreparedStatement statement = conn.prepareStatement("SELECT ID, MSG FROM MYPREFIX_ACTIVEMQ_MSGS"); + ResultSet result = statement.executeQuery(); + ArrayList results = new ArrayList(); + while(result.next()) { + long id = result.getLong(1); + Message message = (Message)wireFormat.unmarshal(new ByteSequence(result.getBytes(2))); + LOG.info("id: " + id + ", message SeqId: " + message.getMessageId().getBrokerSequenceId() + ", MSG: " + message); + results.add(message); + } + statement.close(); + conn.close(); + + return results; + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + + DefaultJDBCAdapter adapter = new DefaultJDBCAdapter(); + jdbc.setAdapter(adapter); + + Statements statements = new Statements(); + statements.setTablePrefix("MYPREFIX_"); + jdbc.setStatements(statements); + + jdbc.setUseLock(false); + jdbc.setDataSource(dataSource); + jdbc.deleteAllMessages(); + broker.setPersistenceAdapter(jdbc); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCTestMemory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCTestMemory.java new file mode 100644 index 0000000000..e8bda0786c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCTestMemory.java @@ -0,0 +1,152 @@ +/** + * 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.store.jdbc; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.junit.Ignore; + + +public class JDBCTestMemory extends TestCase { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + Connection conn; + Session sess; + Destination dest; + + BrokerService broker; + + protected void setUp() throws Exception { + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + } + + protected void tearDown() throws Exception { + broker.stop(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setUseJmx(true); + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + + jdbc.deleteAllMessages(); + broker.setPersistenceAdapter(jdbc); + broker.addConnector("tcp://0.0.0.0:61616"); + return broker; + } + + protected BrokerService createRestartedBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setUseJmx(true); + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + broker.setPersistenceAdapter(jdbc); + broker.addConnector("tcp://0.0.0.0:61616"); + return broker; + } + + public void init() throws Exception { + conn = factory.createConnection(); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + dest = sess.createQueue("test"); + } + + @Ignore("requires human input to terminate!") + public void testRecovery() throws Exception { + init(); + MessageProducer producer = sess.createProducer(dest); + for (int i = 0; i < 1000; i++) { + producer.send(sess.createTextMessage("test")); + } + producer.close(); + sess.close(); + conn.close(); + + broker.stop(); + broker.waitUntilStopped(); + broker = createRestartedBroker(); + broker.start(); + broker.waitUntilStarted(); + + init(); + + for (int i = 0; i < 10; i++) { + new Thread("Producer " + i) { + + public void run() { + try { + MessageProducer producer = sess.createProducer(dest); + for (int i = 0; i < 15000; i++) { + producer.send(sess.createTextMessage("test")); + if (i % 100 == 0) { + System.out.println(getName() + " sent message " + i); + } + } + producer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + }.start(); + + new Thread("Consumer " + i) { + + public void run() { + try { + MessageConsumer consumer = sess.createConsumer(dest); + for (int i = 0; i < 15000; i++) { + consumer.receive(2000); + if (i % 100 == 0) { + System.out.println(getName() + " received message " + i); + } + } + consumer.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + }.start(); + } + + // Check out JConsole + System.in.read(); + sess.close(); + conn.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCXACommitExceptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCXACommitExceptionTest.java new file mode 100644 index 0000000000..2713f9fb34 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/jdbc/JDBCXACommitExceptionTest.java @@ -0,0 +1,159 @@ +/** + * 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.store.jdbc; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.XAConnection; +import javax.jms.XASession; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +import org.apache.activemq.ActiveMQXAConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// https://issues.apache.org/activemq/browse/AMQ-2880 +public class JDBCXACommitExceptionTest extends JDBCCommitExceptionTest { + private static final Logger LOG = LoggerFactory.getLogger(JDBCXACommitExceptionTest.class); + + private long txGenerator = System.currentTimeMillis(); + + protected ActiveMQXAConnectionFactory factory; + + boolean onePhase = true; + + @Override + public void setUp() throws Exception { + super.setUp(); + + factory = new ActiveMQXAConnectionFactory( + connectionUri + "?jms.prefetchPolicy.all=0&jms.redeliveryPolicy.maximumRedeliveries="+messagesExpected); + } + + public void testTwoPhaseSqlException() throws Exception { + onePhase = false; + doTestSqlException(); + } + + @Override + protected int receiveMessages(int messagesExpected) throws Exception { + XAConnection connection = factory.createXAConnection(); + connection.start(); + XASession session = connection.createXASession(); + + jdbc.setShouldBreak(true); + + // first try and receive these messages, they'll continually fail + receiveMessages(messagesExpected, session, onePhase); + + jdbc.setShouldBreak(false); + + // now that the store is sane, try and get all the messages sent + return receiveMessages(messagesExpected, session, onePhase); + } + + protected int receiveMessages(int messagesExpected, XASession session, boolean onePhase) throws Exception { + int messagesReceived = 0; + + for (int i=0; i lockedSet = new HashSet(); + ExecutorService executor = Executors.newCachedThreadPool(); + executor.execute(new Runnable() { + @Override + public void run() { + try { + lockerA.start(); + lockedSet.add(lockerA); + printLockTable(connection); + + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + executor.execute(new Runnable() { + @Override + public void run() { + try { + lockerB.start(); + lockedSet.add(lockerB); + printLockTable(connection); + + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + // sleep for a bit till both are alive + TimeUnit.SECONDS.sleep(2); + assertTrue("no start", lockedSet.isEmpty()); + assertFalse("A is blocked", lockerA.keepAlive()); + assertFalse("B is blocked", lockerB.keepAlive()); + + LOG.info("releasing phony lock " + fakeId); + + statement = connection.prepareStatement(jdbc.getStatements().getLeaseUpdateStatement()); + statement.setString(1, null); + statement.setLong(2, 0l); + statement.setString(3, fakeId); + assertEquals("we released " + fakeId, 1, statement.executeUpdate()); + LOG.info("released " + fakeId); + printLockTable(connection); + + TimeUnit.MILLISECONDS.sleep(AbstractLocker.DEFAULT_LOCK_ACQUIRE_SLEEP_INTERVAL); + assertEquals("one locker started", 1, lockedSet.size()); + + assertTrue("one isAlive", lockerA.keepAlive() || lockerB.keepAlive()); + + LeaseDatabaseLocker winner = lockedSet.iterator().next(); + winner.stop(); + lockedSet.remove(winner); + + TimeUnit.MILLISECONDS.sleep(AbstractLocker.DEFAULT_LOCK_ACQUIRE_SLEEP_INTERVAL); + assertEquals("one locker started", 1, lockedSet.size()); + + lockedSet.iterator().next().stop(); + printLockTable(connection); + } + + @Test + public void testDiffOffsetAhead() throws Exception { + LeaseDatabaseLocker underTest = new LeaseDatabaseLocker(); + assertTrue("when ahead of db adjustment is negative", callDiffOffset(underTest, System.currentTimeMillis() - 60000) < 0); + } + + @Test + public void testDiffOffsetBehind() throws Exception { + LeaseDatabaseLocker underTest = new LeaseDatabaseLocker(); + assertTrue("when behind db adjustment is positive", callDiffOffset(underTest, System.currentTimeMillis() + 60000) > 0); + } + + @Test + public void testDiffIngoredIfLessthanMaxAllowableDiffFromDBTime() throws Exception { + LeaseDatabaseLocker underTest = new LeaseDatabaseLocker(); + underTest.setMaxAllowableDiffFromDBTime(60000); + assertEquals("no adjust when under limit", 0, callDiffOffset(underTest,System.currentTimeMillis() - 40000 )); + } + + public long callDiffOffset(LeaseDatabaseLocker underTest, final long dbTime) throws Exception { + + Mockery context = new Mockery() {{ + setImposteriser(ClassImposteriser.INSTANCE); + }}; + final Statements statements = context.mock(Statements.class); + final JDBCPersistenceAdapter jdbcPersistenceAdapter = context.mock(JDBCPersistenceAdapter.class); + final Connection connection = context.mock(Connection.class); + final PreparedStatement preparedStatement = context.mock(PreparedStatement.class); + final ResultSet resultSet = context.mock(ResultSet.class); + final Timestamp timestamp = context.mock(Timestamp.class); + + context.checking(new Expectations() {{ + allowing(jdbcPersistenceAdapter).getStatements(); + will(returnValue(statements)); + allowing(jdbcPersistenceAdapter); + allowing(statements); + allowing(connection).prepareStatement(with(any(String.class))); + will(returnValue(preparedStatement)); + allowing(connection); + allowing(preparedStatement).executeQuery(); + will(returnValue(resultSet)); + allowing(resultSet).next(); + will(returnValue(true)); + allowing(resultSet).getTimestamp(1); + will(returnValue(timestamp)); + allowing(timestamp).getTime(); + will(returnValue(dbTime)); + }}); + + underTest.configure(jdbcPersistenceAdapter); + underTest.setLockable(jdbcPersistenceAdapter); + return underTest.determineTimeDifference(connection); + } + + private void printLockTable(Connection connection) throws Exception { + DefaultJDBCAdapter.printQuery(connection, "SELECT * from ACTIVEMQ_LOCK", System.err); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/CustomLockerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/CustomLockerTest.java new file mode 100644 index 0000000000..bc1e127b66 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/CustomLockerTest.java @@ -0,0 +1,31 @@ +/** + * 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.store.kahadb; + +import junit.framework.TestCase; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; + +public class CustomLockerTest extends TestCase { + + public void testCustomLocker() throws Exception { + BrokerService broker = BrokerFactory.createBroker("xbean:org/apache/activemq/store/kahadb/shared.xml"); + broker.waitUntilStarted(); + broker.stop(); + broker.waitUntilStopped(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBFastEnqueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBFastEnqueueTest.java new file mode 100644 index 0000000000..15abe3d764 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBFastEnqueueTest.java @@ -0,0 +1,245 @@ +/** + * 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.store.kahadb; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Vector; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.BytesMessage; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionControl; +import org.apache.activemq.store.kahadb.disk.journal.FileAppender; +import org.apache.activemq.store.kahadb.disk.journal.Journal; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KahaDBFastEnqueueTest { + private static final Logger LOG = LoggerFactory.getLogger(KahaDBFastEnqueueTest.class); + private BrokerService broker; + private ActiveMQConnectionFactory connectionFactory; + KahaDBPersistenceAdapter kahaDBPersistenceAdapter; + private final Destination destination = new ActiveMQQueue("Test"); + private final String payloadString = new String(new byte[6*1024]); + private final boolean useBytesMessage= true; + private final int parallelProducer = 20; + private final Vector exceptions = new Vector(); + long toSend = 10000; + + // use with: + // -Xmx4g -Dorg.apache.kahadb.journal.appender.WRITE_STAT_WINDOW=10000 -Dorg.apache.kahadb.journal.CALLER_BUFFER_APPENDER=true + @Test + public void testPublishNoConsumer() throws Exception { + + startBroker(true, 10); + + final AtomicLong sharedCount = new AtomicLong(toSend); + long start = System.currentTimeMillis(); + ExecutorService executorService = Executors.newCachedThreadPool(); + for (int i=0; i< parallelProducer; i++) { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + publishMessages(sharedCount, 0); + } catch (Exception e) { + exceptions.add(e); + } + } + }); + } + executorService.shutdown(); + executorService.awaitTermination(30, TimeUnit.MINUTES); + assertTrue("Producers done in time", executorService.isTerminated()); + assertTrue("No exceptions: " + exceptions, exceptions.isEmpty()); + long totalSent = toSend * payloadString.length(); + + double duration = System.currentTimeMillis() - start; + stopBroker(); + LOG.info("Duration: " + duration + "ms"); + LOG.info("Rate: " + (toSend * 1000/duration) + "m/s"); + LOG.info("Total send: " + totalSent); + LOG.info("Total journal write: " + kahaDBPersistenceAdapter.getStore().getJournal().length()); + LOG.info("Total index size " + kahaDBPersistenceAdapter.getStore().getPageFile().getDiskSize()); + LOG.info("Total store size: " + kahaDBPersistenceAdapter.size()); + LOG.info("Journal writes %: " + kahaDBPersistenceAdapter.getStore().getJournal().length() / (double)totalSent * 100 + "%"); + + restartBroker(0, 1200000); + consumeMessages(toSend); + } + + @Test + public void testPublishNoConsumerNoCheckpoint() throws Exception { + + toSend = 100; + startBroker(true, 0); + + final AtomicLong sharedCount = new AtomicLong(toSend); + long start = System.currentTimeMillis(); + ExecutorService executorService = Executors.newCachedThreadPool(); + for (int i=0; i< parallelProducer; i++) { + executorService.execute(new Runnable() { + @Override + public void run() { + try { + publishMessages(sharedCount, 0); + } catch (Exception e) { + exceptions.add(e); + } + } + }); + } + executorService.shutdown(); + executorService.awaitTermination(30, TimeUnit.MINUTES); + assertTrue("Producers done in time", executorService.isTerminated()); + assertTrue("No exceptions: " + exceptions, exceptions.isEmpty()); + long totalSent = toSend * payloadString.length(); + + broker.getAdminView().gc(); + + + double duration = System.currentTimeMillis() - start; + stopBroker(); + LOG.info("Duration: " + duration + "ms"); + LOG.info("Rate: " + (toSend * 1000/duration) + "m/s"); + LOG.info("Total send: " + totalSent); + LOG.info("Total journal write: " + kahaDBPersistenceAdapter.getStore().getJournal().length()); + LOG.info("Total index size " + kahaDBPersistenceAdapter.getStore().getPageFile().getDiskSize()); + LOG.info("Total store size: " + kahaDBPersistenceAdapter.size()); + LOG.info("Journal writes %: " + kahaDBPersistenceAdapter.getStore().getJournal().length() / (double)totalSent * 100 + "%"); + + restartBroker(0, 0); + consumeMessages(toSend); + } + + private void consumeMessages(long count) throws Exception { + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.setWatchTopicAdvisories(false); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + for (int i=0; i 0) { + Message message = null; + if (useBytesMessage) { + message = session.createBytesMessage(); + ((BytesMessage) message).writeBytes(payloadString.getBytes()); + } else { + message = session.createTextMessage(payloadString); + } + producer.send(message, DeliveryMode.PERSISTENT, 5, expiry); + if (i != toSend && i%sampleRate == 0) { + long now = System.currentTimeMillis(); + LOG.info("Remainder: " + i + ", rate: " + sampleRate * 1000 / (now - start) + "m/s" ); + start = now; + } + } + connection.syncSendPacket(new ConnectionControl()); + connection.close(); + } + + public void startBroker(boolean deleteAllMessages, int checkPointPeriod) throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter)broker.getPersistenceAdapter(); + kahaDBPersistenceAdapter.setEnableJournalDiskSyncs(false); + // defer checkpoints which require a sync + kahaDBPersistenceAdapter.setCleanupInterval(checkPointPeriod); + kahaDBPersistenceAdapter.setCheckpointInterval(checkPointPeriod); + + // optimise for disk best batch rate + kahaDBPersistenceAdapter.setJournalMaxWriteBatchSize(24*1024*1024); //4mb default + kahaDBPersistenceAdapter.setJournalMaxFileLength(128*1024*1024); // 32mb default + // keep index in memory + kahaDBPersistenceAdapter.setIndexCacheSize(500000); + kahaDBPersistenceAdapter.setIndexWriteBatchSize(500000); + kahaDBPersistenceAdapter.setEnableIndexRecoveryFile(false); + kahaDBPersistenceAdapter.setEnableIndexDiskSyncs(false); + + broker.addConnector("tcp://0.0.0.0:0"); + broker.start(); + + String options = "?jms.watchTopicAdvisories=false&jms.useAsyncSend=true&jms.alwaysSessionAsync=false&jms.dispatchAsync=false&socketBufferSize=131072&ioBufferSize=16384&wireFormat.tightEncodingEnabled=false&wireFormat.cacheSize=8192"; + connectionFactory = new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri() + options); + } + + @Test + public void testRollover() throws Exception { + byte flip = 0x1; + for (long i=0; iHiram Chirino + */ +public class KahaDBPersistenceAdapterTest extends PersistenceAdapterTestSupport { + + protected PersistenceAdapter createPersistenceAdapter(boolean delete) throws IOException { + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(new File("target/activemq-data/kahadb")); + if (delete) { + kaha.deleteAllMessages(); + } + return kaha; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreBrokerTest.java new file mode 100644 index 0000000000..2152501606 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreBrokerTest.java @@ -0,0 +1,67 @@ +/** + * 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.store.kahadb; + +import java.io.File; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTest; +import org.apache.activemq.util.IOHelper; + +/** + * Once the wire format is completed we can test against real persistence storage. + * + * + */ +public class KahaDBStoreBrokerTest extends BrokerTest { + + protected void setUp() throws Exception { + this.setAutoFail(true); + super.setUp(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + KahaDBStore kaha = new KahaDBStore(); + File directory = new File("target/activemq-data/kahadb"); + IOHelper.deleteChildren(directory); + kaha.setDirectory(directory); + kaha.deleteAllMessages(); + broker.setPersistenceAdapter(kaha); + return broker; + } + + protected BrokerService createRestartedBroker() throws Exception { + BrokerService broker = new BrokerService(); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(new File("target/activemq-data/kahadb")); + broker.setPersistenceAdapter(kaha); + return broker; + } + + + public static Test suite() { + return suite(KahaDBStoreBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreOrderTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreOrderTest.java new file mode 100644 index 0000000000..8cace613df --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreOrderTest.java @@ -0,0 +1,35 @@ +/** + * 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.store.kahadb; + +import java.io.File; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.StoreOrderTest; + +// https://issues.apache.org/activemq/browse/AMQ-2594 +public class KahaDBStoreOrderTest extends StoreOrderTest { + + @Override + protected void setPersistentAdapter(BrokerService brokerService) + throws Exception { + KahaDBStore kaha = new KahaDBStore(); + File directory = new File("target/activemq-data/kahadb/storeOrder"); + kaha.setDirectory(directory); + brokerService.setPersistenceAdapter(kaha); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreRecoveryBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreRecoveryBrokerTest.java new file mode 100644 index 0000000000..3725572b10 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreRecoveryBrokerTest.java @@ -0,0 +1,213 @@ +/** + * 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.store.kahadb; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; + +import junit.framework.Test; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.RecoveryBrokerTest; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.commons.io.FileUtils; + + +/** + * Used to verify that recovery works correctly against + * + * + */ +public class KahaDBStoreRecoveryBrokerTest extends RecoveryBrokerTest { + public static final String KAHADB_DIR_BASE = "target/activemq-data/kahadb"; + public static String kahaDbDirectoryName; + + enum CorruptionType { None, FailToLoad, LoadInvalid, LoadCorrupt, LoadOrderIndex0 }; + public CorruptionType failTest = CorruptionType.None; + + @Override + protected void setUp() throws Exception { + kahaDbDirectoryName = KAHADB_DIR_BASE + "/" + System.currentTimeMillis(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + try { + File kahaDbDir = new File(kahaDbDirectoryName); + FileUtils.deleteDirectory(kahaDbDir); + } catch (IOException e) { + } + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(new File(kahaDbDirectoryName)); + kaha.deleteAllMessages(); + kaha.setCheckForCorruptJournalFiles(failTest == CorruptionType.LoadOrderIndex0); + broker.setPersistenceAdapter(kaha); + return broker; + } + + @Override + @SuppressWarnings("resource") + protected BrokerService createRestartedBroker() throws Exception { + + // corrupting index + File index = new File(kahaDbDirectoryName + "/db.data"); + RandomAccessFile raf = new RandomAccessFile(index, "rw"); + switch (failTest) { + case FailToLoad: + index.delete(); + raf = new RandomAccessFile(index, "rw"); + raf.seek(index.length()); + raf.writeBytes("corrupt"); + break; + case LoadInvalid: + // page size 0 + raf.seek(0); + raf.writeBytes("corrupt and cannot load metadata"); + break; + case LoadCorrupt: + // loadable but invalid metadata + // location of order index low priority index for first destination... + raf.seek(8*1024 + 57); + raf.writeLong(Integer.MAX_VALUE-10); + break; + case LoadOrderIndex0: + // loadable but invalid metadata + // location of order index default priority index size + // so looks like there are no ids in the order index + // picked up by setCheckForCorruptJournalFiles + raf.seek(12*1024 + 21); + raf.writeShort(0); + raf.writeChar(0); + raf.writeLong(-1); + break; + default: + } + raf.close(); + + // starting broker + BrokerService broker = new BrokerService(); + KahaDBStore kaha = new KahaDBStore(); + kaha.setCheckForCorruptJournalFiles(failTest == CorruptionType.LoadOrderIndex0); + // uncomment if you want to test archiving + //kaha.setArchiveCorruptedIndex(true); + kaha.setDirectory(new File(kahaDbDirectoryName)); + broker.setPersistenceAdapter(kaha); + return broker; + } + + public static Test suite() { + return suite(KahaDBStoreRecoveryBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void initCombosForTestLargeQueuePersistentMessagesNotLostOnRestart() { + this.addCombinationValues("failTest", new CorruptionType[]{CorruptionType.FailToLoad, CorruptionType.LoadInvalid, CorruptionType.LoadCorrupt, CorruptionType.LoadOrderIndex0} ); + } + + public void testLargeQueuePersistentMessagesNotLostOnRestart() throws Exception { + + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + + // Setup the producer and send the message. + StubConnection connection = createConnection(); + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + ArrayList expected = new ArrayList(); + + int MESSAGE_COUNT = 10000; + for(int i=0; i < MESSAGE_COUNT; i++) { + Message message = createMessage(producerInfo, destination); + message.setPersistent(true); + connection.send(message); + expected.add(message.getMessageId().toString()); + } + connection.request(closeConnectionInfo(connectionInfo)); + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + producerInfo = createProducerInfo(sessionInfo); + connection.send(producerInfo); + + for(int i=0; i < MESSAGE_COUNT/2; i++) { + Message m = receiveMessage(connection); + assertNotNull("Should have received message "+expected.get(0)+" by now!", m); + assertEquals(expected.remove(0), m.getMessageId().toString()); + MessageAck ack = createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE); + connection.send(ack); + } + + connection.request(closeConnectionInfo(connectionInfo)); + + // restart the broker. + restartBroker(); + + // Setup the consumer and receive the message. + connection = createConnection(); + connectionInfo = createConnectionInfo(); + sessionInfo = createSessionInfo(connectionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + consumerInfo = createConsumerInfo(sessionInfo, destination); + connection.send(consumerInfo); + + for(int i=0; i < MESSAGE_COUNT/2; i++) { + Message m = receiveMessage(connection); + assertNotNull("Should have received message "+expected.get(i)+" by now!", m); + assertEquals(expected.get(i), m.getMessageId().toString()); + MessageAck ack = createAck(consumerInfo, m, 1, MessageAck.STANDARD_ACK_TYPE); + connection.send(ack); + + + } + + connection.request(closeConnectionInfo(connectionInfo)); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreRecoveryExpiryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreRecoveryExpiryTest.java new file mode 100644 index 0000000000..754cf1aff6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBStoreRecoveryExpiryTest.java @@ -0,0 +1,113 @@ +/** + * 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.store.kahadb; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.concurrent.TimeUnit; + +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.BaseDestination; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class KahaDBStoreRecoveryExpiryTest { + + private BrokerService broker; + private ActiveMQConnection connection; + private final Destination destination = new ActiveMQQueue("Test"); + private Session session; + + @Test + public void testRestartWitExpired() throws Exception { + publishMessages(1, 0); + publishMessages(1, 2000); + publishMessages(1, 0); + restartBroker(3000); + consumeMessages(2); + } + + @Test + public void testRestartWitExpiredLargerThanBatchRecovery() throws Exception { + publishMessages(BaseDestination.MAX_PAGE_SIZE + 10, 2000); + publishMessages(10, 0); + restartBroker(3000); + consumeMessages(10); + } + + private void consumeMessages(int count) throws Exception { + MessageConsumer consumer = session.createConsumer(destination); + for (int i=0; i exceptions = new Vector(); + + @Before + public void initStore() throws Exception { + ActiveMQDestination destination = new ActiveMQQueue("Test"); + store = new KahaDBStore(); + store.setMaxAsyncJobs(100); + store.setDeleteAllMessages(true); + store.start(); + underTest = store.new KahaDBMessageStore(destination); + underTest.start(); + message = new ActiveMQMessage(); + message.setDestination(destination); + } + + @After + public void destroyStore() throws Exception { + if (store != null) { + store.stop(); + } + } + + @Test + public void testConcurrentStoreAndDispatchQueue() throws Exception { + + ExecutorService executor = Executors.newCachedThreadPool(); + for (int i=0; i 800 ); + assertTrue( count < 1000 ); + + broker.stop(); + } + + + public void testCheckCorruptionNotIgnored() throws Exception { + KahaDBStore kaha = createStore(true); + assertTrue(kaha.isChecksumJournalFiles()); + assertFalse(kaha.isCheckForCorruptJournalFiles()); + + kaha.setJournalMaxFileLength(1024*100); + kaha.setChecksumJournalFiles(true); + BrokerService broker = createBroker(kaha); + sendMessages(1000); + broker.stop(); + + // Modify/Corrupt some journal files.. + assertExistsAndCorrupt(new File(kaha.getDirectory(), "db-4.log")); + assertExistsAndCorrupt(new File(kaha.getDirectory(), "db-8.log")); + + kaha = createStore(false); + kaha.setJournalMaxFileLength(1024*100); + kaha.setChecksumJournalFiles(true); + kaha.setCheckForCorruptJournalFiles(true); + assertFalse(kaha.isIgnoreMissingJournalfiles()); + try { + broker = createBroker(kaha); + fail("expected IOException"); + } catch (IOException e) { + assertTrue( e.getMessage().startsWith("Detected missing/corrupt journal files") ); + } + + } + + + public void testMigrationOnNewDefaultForChecksumJournalFiles() throws Exception { + KahaDBStore kaha = createStore(true); + kaha.setChecksumJournalFiles(false); + assertFalse(kaha.isChecksumJournalFiles()); + assertFalse(kaha.isCheckForCorruptJournalFiles()); + + kaha.setJournalMaxFileLength(1024*100); + BrokerService broker = createBroker(kaha); + sendMessages(1000); + broker.stop(); + + kaha = createStore(false); + kaha.setJournalMaxFileLength(1024*100); + kaha.setCheckForCorruptJournalFiles(true); + assertFalse(kaha.isIgnoreMissingJournalfiles()); + createBroker(kaha); + assertEquals(1000, receiveMessages()); + } + + + private void assertExistsAndCorrupt(File file) throws IOException { + assertTrue(file.exists()); + RandomAccessFile f = new RandomAccessFile(file, "rw"); + try { + f.seek(1024*5+134); + f.write("... corruption string ...".getBytes()); + } finally { + f.close(); + } + } + + + public void testCheckCorruptionIgnored() throws Exception { + KahaDBStore kaha = createStore(true); + kaha.setJournalMaxFileLength(1024*100); + BrokerService broker = createBroker(kaha); + sendMessages(1000); + broker.stop(); + + // Delete some journal files.. + assertExistsAndCorrupt(new File(kaha.getDirectory(), "db-4.log")); + assertExistsAndCorrupt(new File(kaha.getDirectory(), "db-8.log")); + + kaha = createStore(false); + kaha.setIgnoreMissingJournalfiles(true); + kaha.setJournalMaxFileLength(1024*100); + kaha.setCheckForCorruptJournalFiles(true); + broker = createBroker(kaha); + + // We know we won't get all the messages but we should get most of them. + int count = receiveMessages(); + assertTrue("Expected to received a min # of messages.. Got: "+count, count > 990 ); + assertTrue( count < 1000 ); + + broker.stop(); + } + + private void assertExistsAndDelete(File file) { + assertTrue(file.exists()); + file.delete(); + assertFalse(file.exists()); + } + + private void sendMessages(int count) throws JMSException { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + try { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(new ActiveMQQueue("TEST")); + for (int i = 0; i < count; i++) { + producer.send(session.createTextMessage(createContent(i))); + } + } finally { + connection.close(); + } + } + + private int receiveMessages() throws JMSException { + int rc=0; + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + try { + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer messageConsumer = session.createConsumer(new ActiveMQQueue("TEST")); + while ( messageConsumer.receive(1000) !=null ) { + rc++; + } + return rc; + } finally { + connection.close(); + } + } + + private String createContent(int i) { + StringBuilder sb = new StringBuilder(i+":"); + while( sb.length() < 1024 ) { + sb.append("*"); + } + return sb.toString(); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion1/db-1.log b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion1/db-1.log new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion1/db.data b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion1/db.data new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion1/db.redo b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion1/db.redo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion2/db-1.log b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion2/db-1.log new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion2/db.data b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion2/db.data new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion2/db.redo b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion2/db.redo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion3/db-1.log b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion3/db-1.log new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion3/db.data b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion3/db.data new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion3/db.redo b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion3/db.redo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion4/db-1.log b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion4/db-1.log new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion4/db.data b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion4/db.data new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion4/db.redo b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersion4/db.redo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersionTest.java new file mode 100644 index 0000000000..c03f60db01 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/KahaDBVersionTest.java @@ -0,0 +1,179 @@ +/** + * 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.store.kahadb; + +import java.io.File; +import java.io.IOException; +import java.security.ProtectionDomain; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.IOHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author chirino + */ +public class KahaDBVersionTest extends TestCase { + static String basedir; + static { + try { + ProtectionDomain protectionDomain = KahaDBVersionTest.class.getProtectionDomain(); + basedir = new File(new File(protectionDomain.getCodeSource().getLocation().getPath()), "../..").getCanonicalPath(); + } catch (IOException e) { + basedir = "."; + } + } + + static final Logger LOG = LoggerFactory.getLogger(KahaDBVersionTest.class); + final static File VERSION_1_DB = new File(basedir + "/src/test/resources/org/apache/activemq/store/kahadb/KahaDBVersion1"); + final static File VERSION_2_DB = new File(basedir + "/src/test/resources/org/apache/activemq/store/kahadb/KahaDBVersion2"); + final static File VERSION_3_DB = new File(basedir + "/src/test/resources/org/apache/activemq/store/kahadb/KahaDBVersion3"); + final static File VERSION_4_DB = new File(basedir + "/src/test/resources/org/apache/activemq/store/kahadb/KahaDBVersion4"); + + BrokerService broker = null; + + protected BrokerService createBroker(KahaDBPersistenceAdapter kaha) throws Exception { + broker = new BrokerService(); + broker.setUseJmx(false); + broker.setPersistenceAdapter(kaha); + broker.start(); + return broker; + } + + @Override + protected void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + public void XtestCreateStore() throws Exception { + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + File dir = new File("src/test/resources/org/apache/activemq/store/kahadb/KahaDBVersion4"); + IOHelper.deleteFile(dir); + kaha.setDirectory(dir); + kaha.setJournalMaxFileLength(1024 * 1024); + BrokerService broker = createBroker(kaha); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.setClientID("test"); + connection.start(); + producerSomeMessages(connection, 1000); + connection.close(); + broker.stop(); + } + + private void producerSomeMessages(Connection connection, int numToSend) throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("test.topic"); + Queue queue = session.createQueue("test.queue"); + MessageConsumer consumer = session.createDurableSubscriber(topic, "test"); + consumer.close(); + MessageProducer producer = session.createProducer(topic); + producer.setPriority(9); + for (int i = 0; i < numToSend; i++) { + Message msg = session.createTextMessage("test message:" + i); + producer.send(msg); + } + LOG.info("sent " + numToSend + " to topic"); + producer = session.createProducer(queue); + for (int i = 0; i < numToSend; i++) { + Message msg = session.createTextMessage("test message:" + i); + producer.send(msg); + } + LOG.info("sent " + numToSend + " to queue"); + } + + public void testVersion1Conversion() throws Exception { + doConvertRestartCycle(VERSION_1_DB); + } + + public void testVersion2Conversion() throws Exception { + doConvertRestartCycle(VERSION_2_DB); + } + + public void testVersion3Conversion() throws Exception { + doConvertRestartCycle(VERSION_3_DB); + } + + public void testVersion4Conversion() throws Exception { + doConvertRestartCycle(VERSION_4_DB); + } + + public void doConvertRestartCycle(File existingStore) throws Exception { + + File testDir = new File("target/activemq-data/kahadb/versionDB"); + IOHelper.deleteFile(testDir); + IOHelper.copyFile(existingStore, testDir); + final int numToSend = 1000; + + // on repeat store will be upgraded + for (int repeats = 0; repeats < 3; repeats++) { + KahaDBPersistenceAdapter kaha = new KahaDBPersistenceAdapter(); + kaha.setDirectory(testDir); + kaha.setJournalMaxFileLength(1024 * 1024); + BrokerService broker = createBroker(kaha); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = cf.createConnection(); + connection.setClientID("test"); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("test.topic"); + Queue queue = session.createQueue("test.queue"); + + if (repeats > 0) { + // upgraded store will be empty so generated some more messages + producerSomeMessages(connection, numToSend); + } + + MessageConsumer queueConsumer = session.createConsumer(queue); + int count = 0; + for (int i = 0; i < (repeats == 0 ? 1000 : numToSend); i++) { + TextMessage msg = (TextMessage) queueConsumer.receive(10000); + count++; + // System.err.println(msg.getText()); + assertNotNull(msg); + } + LOG.info("Consumed " + count + " from queue"); + count = 0; + MessageConsumer topicConsumer = session.createDurableSubscriber(topic, "test"); + for (int i = 0; i < (repeats == 0 ? 1000 : numToSend); i++) { + TextMessage msg = (TextMessage) topicConsumer.receive(10000); + count++; + // System.err.println(msg.getText()); + assertNotNull("" + count, msg); + } + LOG.info("Consumed " + count + " from topic"); + connection.close(); + + broker.stop(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/NoSpaceIOTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/NoSpaceIOTest.java new file mode 100644 index 0000000000..fd61f89b2d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/NoSpaceIOTest.java @@ -0,0 +1,120 @@ +/** + * 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.store.kahadb; + +import java.io.File; +import java.io.RandomAccessFile; +import java.util.concurrent.atomic.AtomicLong; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.junit.Ignore; +import org.junit.Test; + +public class NoSpaceIOTest { + private static final Logger LOG = LoggerFactory.getLogger(NoSpaceIOTest.class); + + // need an app to input to console in intellij idea + public static void main(String[] args) throws Exception { + new NoSpaceIOTest().testRunOutOfSpace(); + } + + // handy way to validate some out of space related errors with a usb key + // allow it to run out of space, delete toDelete and see it recover + @Ignore("needs small volume, like usb key") + @Test + public void testRunOutOfSpace() throws Exception { + BrokerService broker = new BrokerService(); + File dataDir = new File("/Volumes/NO NAME/"); + File useUpSpace = new File(dataDir, "bigFile"); + if (!useUpSpace.exists()) { + LOG.info("using up some space..."); + RandomAccessFile filler = new RandomAccessFile(useUpSpace, "rw"); + filler.setLength(1024*1024*1212); // use ~1.xG of 2G (usb) volume + filler.close(); + File toDelete = new File(dataDir, "toDelete"); + filler = new RandomAccessFile(toDelete, "rw"); + filler.setLength(1024*1024*32*10); // 10 data files + filler.close(); + } + broker.setDataDirectoryFile(dataDir); + broker.start(); + AtomicLong consumed = new AtomicLong(0); + consume(consumed); + LOG.info("consumed: " + consumed); + + broker.getPersistenceAdapter().checkpoint(true); + + AtomicLong sent = new AtomicLong(0); + try { + produce(sent, 200); + } catch (Exception expected) { + LOG.info("got ex, sent: " + sent); + } + LOG.info("sent: " + sent); + System.out.println("Remove toDelete file and press any key to continue"); + int read = System.in.read(); + System.err.println("read:" + read); + + LOG.info("Trying to send again: " + sent); + try { + produce(sent, 200); + } catch (Exception expected) { + LOG.info("got ex, sent: " + sent); + } + LOG.info("sent: " + sent); + } + + private void consume(AtomicLong consumed) throws JMSException { + Connection c = new ActiveMQConnectionFactory("vm://localhost").createConnection(); + try { + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = s.createConsumer(new ActiveMQQueue("t")); + while (consumer.receive(2000) != null) { + consumed.incrementAndGet(); + } + } finally { + c.close(); + } + } + + private void produce(AtomicLong sent, long toSend) throws JMSException { + Connection c = new ActiveMQConnectionFactory("vm://localhost").createConnection(); + try { + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = s.createProducer(new ActiveMQQueue("t")); + TextMessage m = s.createTextMessage(); + m.setText(String.valueOf(new char[1024*1024])); + for (int i=0; iHiram Chirino + */ +public class KahaDBFilePendingMessageCursorTest extends FilePendingMessageCursorTestSupport { + + @Test + public void testAddRemoveAddIndexSize() throws Exception { + brokerService = new BrokerService(); + brokerService.setUseJmx(false); + SystemUsage usage = brokerService.getSystemUsage(); + usage.getMemoryUsage().setLimit(1024*150); + String body = new String(new byte[1024]); + Destination destination = new Queue(brokerService, new ActiveMQQueue("Q"), null, new DestinationStatistics(), null); + + underTest = new FilePendingMessageCursor(brokerService.getBroker(), "test", false); + underTest.setSystemUsage(usage); + + LOG.info("start"); + final PageFile pageFile = ((PListImpl)underTest.getDiskList()).getPageFile(); + LOG.info("page count: " +pageFile.getPageCount()); + LOG.info("free count: " + pageFile.getFreePageCount()); + LOG.info("content size: " +pageFile.getPageContentSize()); + + final long initialPageCount = pageFile.getPageCount(); + + final int numMessages = 1000; + + for (int j=0; j<10; j++) { + // ensure free pages are reused + for (int i=0; i< numMessages; i++) { + ActiveMQMessage mqMessage = new ActiveMQMessage(); + mqMessage.setStringProperty("body", body); + mqMessage.setMessageId(new MessageId("1:2:3:" + i)); + mqMessage.setMemoryUsage(usage.getMemoryUsage()); + mqMessage.setRegionDestination(destination); + underTest.addMessageLast(new IndirectMessageReference(mqMessage)); + } + assertFalse("cursor is not full " + usage.getTempUsage(), underTest.isFull()); + + underTest.reset(); + long receivedCount = 0; + while(underTest.hasNext()) { + MessageReference ref = underTest.next(); + underTest.remove(); + ref.decrementReferenceCount(); + assertEquals("id is correct", receivedCount++, ref.getMessageId().getProducerSequenceId()); + } + assertEquals("got all messages back", receivedCount, numMessages); + LOG.info("page count: " +pageFile.getPageCount()); + LOG.info("free count: " + pageFile.getFreePageCount()); + LOG.info("content size: " + pageFile.getPageContentSize()); + } + + assertEquals("expected page usage", initialPageCount, pageFile.getPageCount() - pageFile.getFreePageCount() ); + + LOG.info("Destroy"); + underTest.destroy(); + LOG.info("page count: " + pageFile.getPageCount()); + LOG.info("free count: " + pageFile.getFreePageCount()); + LOG.info("content size: " + pageFile.getPageContentSize()); + assertEquals("expected page usage", initialPageCount -1, pageFile.getPageCount() - pageFile.getFreePageCount() ); + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/plist/PListTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/plist/PListTest.java new file mode 100644 index 0000000000..555503e8e7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/plist/PListTest.java @@ -0,0 +1,660 @@ +/** + * 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.store.kahadb.plist; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Vector; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.apache.activemq.store.PList; +import org.apache.activemq.store.PListEntry; +import org.apache.activemq.util.ByteSequence; +import org.apache.activemq.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PListTest { + static final Logger LOG = LoggerFactory.getLogger(PListTest.class); + private PListStoreImpl store; + private PListImpl plist; + final ByteSequence payload = new ByteSequence(new byte[400]); + final String idSeed = new String("Seed" + new byte[1024]); + final Vector exceptions = new Vector(); + ExecutorService executor; + + private PListEntry getFirst(PList plist) throws IOException { + PList.PListIterator iterator = plist.iterator(); + try { + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } finally { + iterator.release(); + } + } + + @Test + public void testAddLast() throws Exception { + final int COUNT = 1000; + Map map = new LinkedHashMap(); + for (int i = 0; i < COUNT; i++) { + String test = new String("test" + i); + ByteSequence bs = new ByteSequence(test.getBytes()); + map.put(test, bs); + plist.addLast(test, bs); + } + assertEquals(plist.size(), COUNT); + int count = 0; + for (ByteSequence bs : map.values()) { + String origStr = new String(bs.getData(), bs.getOffset(), bs.getLength()); + PListEntry entry = plist.get(count); + String plistString = new String(entry.getByteSequence().getData(), entry.getByteSequence().getOffset(), entry.getByteSequence().getLength()); + assertEquals(origStr, plistString); + count++; + } + } + + @Test + public void testAddFirst() throws Exception { + final int COUNT = 1000; + Map map = new LinkedHashMap(); + for (int i = 0; i < COUNT; i++) { + String test = new String("test" + i); + ByteSequence bs = new ByteSequence(test.getBytes()); + map.put(test, bs); + plist.addFirst(test, bs); + } + assertEquals(plist.size(), COUNT); + long count = plist.size() - 1; + for (ByteSequence bs : map.values()) { + String origStr = new String(bs.getData(), bs.getOffset(), bs.getLength()); + PListEntry entry = plist.get(count); + String plistString = new String(entry.getByteSequence().getData(), entry.getByteSequence().getOffset(), entry.getByteSequence().getLength()); + assertEquals(origStr, plistString); + count--; + } + } + + @Test + public void testRemove() throws IOException { + doTestRemove(2000); + } + + protected void doTestRemove(final int COUNT) throws IOException { + Map map = new LinkedHashMap(); + for (int i = 0; i < COUNT; i++) { + String test = new String("test" + i); + ByteSequence bs = new ByteSequence(test.getBytes()); + map.put(test, bs); + plist.addLast(test, bs); + } + assertEquals(plist.size(), COUNT); + PListEntry entry = plist.getFirst(); + while (entry != null) { + plist.remove(entry.getId()); + entry = plist.getFirst(); + } + assertEquals(0, plist.size()); + } + + @Test + public void testDestroy() throws Exception { + doTestRemove(1); + plist.destroy(); + assertEquals(0, plist.size()); + } + + @Test + public void testDestroyNonEmpty() throws Exception { + final int COUNT = 1000; + Map map = new LinkedHashMap(); + for (int i = 0; i < COUNT; i++) { + String test = new String("test" + i); + ByteSequence bs = new ByteSequence(test.getBytes()); + map.put(test, bs); + plist.addLast(test, bs); + } + plist.destroy(); + assertEquals(0, plist.size()); + } + + @Test + public void testRemoveSecond() throws Exception { + plist.addLast("First", new ByteSequence("A".getBytes())); + plist.addLast("Second", new ByteSequence("B".getBytes())); + + assertTrue(plist.remove("Second")); + assertTrue(plist.remove("First")); + assertFalse(plist.remove("doesNotExist")); + } + + @Test + public void testRemoveSingleEntry() throws Exception { + plist.addLast("First", new ByteSequence("A".getBytes())); + + Iterator iterator = plist.iterator(); + while (iterator.hasNext()) { + iterator.next(); + iterator.remove(); + } + } + + @Test + public void testRemoveSecondPosition() throws Exception { + plist.addLast("First", new ByteSequence("A".getBytes())); + plist.addLast("Second", new ByteSequence("B".getBytes())); + + assertTrue(plist.remove(1)); + assertTrue(plist.remove(0)); + assertFalse(plist.remove(0)); + } + + @Test + public void testConcurrentAddRemove() throws Exception { + File directory = store.getDirectory(); + store.stop(); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store = new PListStoreImpl(); + store.setCleanupInterval(400); + store.setDirectory(directory); + store.setJournalMaxFileLength(1024 * 5); + store.setLazyInit(false); + store.start(); + + final ByteSequence payload = new ByteSequence(new byte[1024 * 2]); + + final Vector exceptions = new Vector(); + final int iterations = 1000; + final int numLists = 10; + + final PList[] lists = new PList[numLists]; + String threadName = Thread.currentThread().getName(); + for (int i = 0; i < numLists; i++) { + Thread.currentThread().setName("C:" + String.valueOf(i)); + lists[i] = store.getPList(String.valueOf(i)); + } + Thread.currentThread().setName(threadName); + + executor = Executors.newFixedThreadPool(100); + class A implements Runnable { + @Override + public void run() { + final String threadName = Thread.currentThread().getName(); + try { + for (int i = 0; i < iterations; i++) { + PList candidate = lists[i % numLists]; + Thread.currentThread().setName("ALRF:" + candidate.getName()); + synchronized (plistLocks(candidate)) { + Object locator = candidate.addLast(String.valueOf(i), payload); + getFirst(candidate); + assertTrue(candidate.remove(locator)); + } + } + } catch (Exception error) { + LOG.error("Unexpcted ex", error); + error.printStackTrace(); + exceptions.add(error); + } finally { + Thread.currentThread().setName(threadName); + } + } + }; + + class B implements Runnable { + @Override + public void run() { + final String threadName = Thread.currentThread().getName(); + try { + for (int i = 0; i < iterations; i++) { + PList candidate = lists[i % numLists]; + Thread.currentThread().setName("ALRF:" + candidate.getName()); + synchronized (plistLocks(candidate)) { + Object locator = candidate.addLast(String.valueOf(i), payload); + getFirst(candidate); + assertTrue(candidate.remove(locator)); + } + } + } catch (Exception error) { + error.printStackTrace(); + exceptions.add(error); + } finally { + Thread.currentThread().setName(threadName); + } + } + }; + + executor.execute(new A()); + executor.execute(new A()); + executor.execute(new A()); + executor.execute(new B()); + executor.execute(new B()); + executor.execute(new B()); + + executor.shutdown(); + boolean finishedInTime = executor.awaitTermination(30, TimeUnit.SECONDS); + + assertTrue("no exceptions", exceptions.isEmpty()); + assertTrue("finished ok", finishedInTime); + } + + @Test + public void testConcurrentAddLast() throws Exception { + File directory = store.getDirectory(); + store.stop(); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store = new PListStoreImpl(); + store.setDirectory(directory); + store.start(); + + final int numThreads = 20; + final int iterations = 1000; + executor = Executors.newFixedThreadPool(100); + for (int i = 0; i < numThreads; i++) { + new Job(i, PListTest.TaskType.ADD, iterations).run(); + } + + for (int i = 0; i < numThreads; i++) { + executor.execute(new Job(i, PListTest.TaskType.ITERATE, iterations)); + } + + for (int i = 0; i < 100; i++) { + executor.execute(new Job(i + 20, PListTest.TaskType.ADD, 100)); + } + + executor.shutdown(); + boolean finishedInTime = executor.awaitTermination(60 * 5, TimeUnit.SECONDS); + assertTrue("finished ok", finishedInTime); + } + + @Test + public void testOverFlow() throws Exception { + File directory = store.getDirectory(); + store.stop(); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store = new PListStoreImpl(); + store.setDirectory(directory); + store.start(); + + for (int i = 0; i < 2000; i++) { + new Job(i, PListTest.TaskType.ADD, 5).run(); + + } + LOG.info("After Load index file: " + store.pageFile.getFile().length()); + LOG.info("After remove index file: " + store.pageFile.getFile().length()); + } + + @Test + public void testConcurrentAddRemoveWithPreload() throws Exception { + File directory = store.getDirectory(); + store.stop(); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store = new PListStoreImpl(); + store.setDirectory(directory); + store.setJournalMaxFileLength(1024 * 5); + store.setCleanupInterval(5000); + store.setIndexWriteBatchSize(500); + store.start(); + + final int iterations = 500; + final int numLists = 10; + + // prime the store + + // create/delete + LOG.info("create"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.CREATE, iterations).run(); + } + + LOG.info("delete"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.DELETE, iterations).run(); + } + + LOG.info("fill"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.ADD, iterations).run(); + } + LOG.info("remove"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.REMOVE, iterations).run(); + } + + LOG.info("check empty"); + for (int i = 0; i < numLists; i++) { + assertEquals("empty " + i, 0, store.getPList("List-" + i).size()); + } + + LOG.info("delete again"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.DELETE, iterations).run(); + } + + LOG.info("fill again"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.ADD, iterations).run(); + } + + LOG.info("parallel add and remove"); + executor = Executors.newFixedThreadPool(numLists * 2); + for (int i = 0; i < numLists * 2; i++) { + executor.execute(new Job(i, i >= numLists ? PListTest.TaskType.ADD : PListTest.TaskType.REMOVE, iterations)); + } + + executor.shutdown(); + LOG.info("wait for parallel work to complete"); + boolean finishedInTime = executor.awaitTermination(60 * 5, TimeUnit.SECONDS); + assertTrue("no exceptions", exceptions.isEmpty()); + assertTrue("finished ok", finishedInTime); + } + + // for non determinant issues, increasing this may help diagnose + final int numRepeats = 1; + + @Test + public void testRepeatStressWithCache() throws Exception { + for (int i = 0; i < numRepeats; i++) { + do_testConcurrentAddIterateRemove(true); + } + } + + @Test + public void testRepeatStressWithOutCache() throws Exception { + for (int i = 0; i < numRepeats; i++) { + do_testConcurrentAddIterateRemove(false); + } + } + + public void do_testConcurrentAddIterateRemove(boolean enablePageCache) throws Exception { + File directory = store.getDirectory(); + store.stop(); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store = new PListStoreImpl(); + store.setIndexEnablePageCaching(enablePageCache); + store.setIndexPageSize(2 * 1024); + store.setDirectory(directory); + store.start(); + + final int iterations = 500; + final int numLists = 10; + + LOG.info("create"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.CREATE, iterations).run(); + } + + LOG.info("fill"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.ADD, iterations).run(); + } + + LOG.info("parallel add and remove"); + executor = Executors.newFixedThreadPool(400); + final int numProducer = 5; + final int numConsumer = 10; + for (int i = 0; i < numLists; i++) { + for (int j = 0; j < numProducer; j++) { + executor.execute(new Job(i, PListTest.TaskType.ADD, iterations * 2)); + } + for (int k = 0; k < numConsumer; k++) { + executor.execute(new Job(i, TaskType.ITERATE_REMOVE, iterations / 4)); + } + } + + for (int i = numLists; i < numLists * 10; i++) { + executor.execute(new Job(i, PListTest.TaskType.ADD, iterations)); + } + + executor.shutdown(); + LOG.info("wait for parallel work to complete"); + boolean shutdown = executor.awaitTermination(60 * 60, TimeUnit.SECONDS); + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + assertTrue("test did not timeout ", shutdown); + } + + @Test + public void testConcurrentAddIterate() throws Exception { + File directory = store.getDirectory(); + store.stop(); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + store = new PListStoreImpl(); + store.setIndexPageSize(2 * 1024); + store.setJournalMaxFileLength(1024 * 1024); + store.setDirectory(directory); + store.setCleanupInterval(-1); + store.setIndexEnablePageCaching(false); + store.setIndexWriteBatchSize(100); + store.start(); + + final int iterations = 250; + final int numLists = 10; + + LOG.info("create"); + for (int i = 0; i < numLists; i++) { + new Job(i, PListTest.TaskType.CREATE, iterations).run(); + } + + LOG.info("parallel add and iterate"); + // We want a lot of adds occurring so that new free pages get created + // along + // with overlapping seeks from the iterators so that we are likely to + // seek into + // some bad area in the page file. + executor = Executors.newFixedThreadPool(100); + final int numProducer = 30; + final int numConsumer = 10; + for (int i = 0; i < numLists; i++) { + for (int j = 0; j < numProducer; j++) { + executor.execute(new Job(i, PListTest.TaskType.ADD, iterations)); + } + for (int k = 0; k < numConsumer; k++) { + executor.execute(new Job(i, TaskType.ITERATE, iterations * 2)); + } + } + + executor.shutdown(); + LOG.info("wait for parallel work to complete"); + boolean shutdown = executor.awaitTermination(5 * 60, TimeUnit.SECONDS); + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + assertTrue("test did not timeout ", shutdown); + LOG.info("Num dataFiles:" + store.getJournal().getFiles().size()); + } + + enum TaskType { + CREATE, DELETE, ADD, REMOVE, ITERATE, ITERATE_REMOVE + } + + class Job implements Runnable { + + int id; + TaskType task; + int iterations; + + public Job(int id, TaskType t, int iterations) { + this.id = id; + this.task = t; + this.iterations = iterations; + } + + @Override + public void run() { + final String threadName = Thread.currentThread().getName(); + try { + PListImpl plist = null; + switch (task) { + case CREATE: + Thread.currentThread().setName("C:" + id); + plist = store.getPList(String.valueOf(id)); + LOG.info("Job-" + id + ", CREATE"); + break; + case DELETE: + Thread.currentThread().setName("D:" + id); + store.removePList(String.valueOf(id)); + break; + case ADD: + Thread.currentThread().setName("A:" + id); + plist = store.getPList(String.valueOf(id)); + + for (int j = 0; j < iterations; j++) { + synchronized (plistLocks(plist)) { + if (exceptions.isEmpty()) { + plist.addLast("PL>" + id + idSeed + "-" + j, payload); + } else { + break; + } + } + } + + if (exceptions.isEmpty()) { + LOG.info("Job-" + id + ", Add, done: " + iterations); + } + break; + case REMOVE: + Thread.currentThread().setName("R:" + id); + plist = store.getPList(String.valueOf(id)); + synchronized (plistLocks(plist)) { + + for (int j = iterations - 1; j >= 0; j--) { + plist.remove("PL>" + id + idSeed + "-" + j); + if (j > 0 && j % (iterations / 2) == 0) { + LOG.info("Job-" + id + " Done remove: " + j); + } + } + } + break; + case ITERATE: + Thread.currentThread().setName("I:" + id); + plist = store.getPList(String.valueOf(id)); + int iterateCount = 0; + synchronized (plistLocks(plist)) { + if (exceptions.isEmpty()) { + Iterator iterator = plist.iterator(); + while (iterator.hasNext() && exceptions.isEmpty()) { + iterator.next(); + iterateCount++; + } + + // LOG.info("Job-" + id + " Done iterate: it=" + + // iterator + ", count:" + iterateCount + + // ", size:" + plist.size()); + if (plist.size() != iterateCount) { + System.err.println("Count Wrong: " + iterator); + } + assertEquals("iterate got all " + id + " iterator:" + iterator, plist.size(), iterateCount); + } + } + break; + + case ITERATE_REMOVE: + Thread.currentThread().setName("IRM:" + id); + plist = store.getPList(String.valueOf(id)); + + int removeCount = 0; + synchronized (plistLocks(plist)) { + + Iterator removeIterator = plist.iterator(); + + while (removeIterator.hasNext()) { + removeIterator.next(); + removeIterator.remove(); + if (removeCount++ > iterations) { + break; + } + } + } + LOG.info("Job-" + id + " Done remove: " + removeCount); + break; + + default: + } + + } catch (Exception e) { + LOG.warn("Job[" + id + "] caught exception: " + e.getMessage()); + e.printStackTrace(); + exceptions.add(e); + if (executor != null) { + executor.shutdownNow(); + } + } finally { + Thread.currentThread().setName(threadName); + } + } + } + + Map locks = new HashMap(); + + private Object plistLocks(PList plist) { + Object lock = null; + synchronized (locks) { + if (locks.containsKey(plist)) { + lock = locks.get(plist); + } else { + lock = new Object(); + locks.put(plist, lock); + } + } + return lock; + } + + @Before + public void setUp() throws Exception { + File directory = new File("target/test/PlistDB"); + IOHelper.mkdirs(directory); + IOHelper.deleteChildren(directory); + startStore(directory); + + } + + protected void startStore(File directory) throws Exception { + store = new PListStoreImpl(); + store.setDirectory(directory); + store.start(); + plist = store.getPList("main"); + } + + @After + public void tearDown() throws Exception { + if (executor != null) { + executor.shutdownNow(); + } + store.stop(); + exceptions.clear(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/shared.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/shared.xml new file mode 100644 index 0000000000..5042df87df --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/kahadb/shared.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/leveldb/LevelDBNegativeQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/leveldb/LevelDBNegativeQueueTest.java new file mode 100644 index 0000000000..7ea7d1a4c2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/leveldb/LevelDBNegativeQueueTest.java @@ -0,0 +1,38 @@ +/** + * 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.store.leveldb; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.cursors.NegativeQueueTest; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.util.IOHelper; + +import java.io.File; + +public class LevelDBNegativeQueueTest extends NegativeQueueTest { + + @Override + protected void configureBroker(BrokerService answer) throws Exception { + super.configureBroker(answer); + LevelDBStore levelDBStore = new LevelDBStore(); + File directory = new File("target/activemq-data/leveldb"); + IOHelper.deleteChildren(directory); + levelDBStore.setDirectory(directory); + levelDBStore.deleteAllMessages(); + answer.setPersistenceAdapter(levelDBStore); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/leveldb/LevelDBStoreBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/leveldb/LevelDBStoreBrokerTest.java new file mode 100644 index 0000000000..156e9ca781 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/leveldb/LevelDBStoreBrokerTest.java @@ -0,0 +1,68 @@ +/** + * 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.store.leveldb; + +import java.io.File; + +import junit.framework.Test; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTest; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.leveldb.LevelDBStore; + +/** + * Once the wire format is completed we can test against real persistence storage. + * + * + */ +public class LevelDBStoreBrokerTest extends BrokerTest { + + protected void setUp() throws Exception { + this.setAutoFail(true); + super.setUp(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + LevelDBStore levelDBStore = new LevelDBStore(); + File directory = new File("target/activemq-data/leveldb"); + IOHelper.deleteChildren(directory); + levelDBStore.setDirectory(directory); + levelDBStore.deleteAllMessages(); + broker.setPersistenceAdapter(levelDBStore); + return broker; + } + + protected BrokerService createRestartedBroker() throws Exception { + BrokerService broker = new BrokerService(); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(new File("target/activemq-data/leveldb")); + broker.setPersistenceAdapter(kaha); + return broker; + } + + + public static Test suite() { + return suite(LevelDBStoreBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/schedulerDB/legacy/db-1.log b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/schedulerDB/legacy/db-1.log new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/schedulerDB/legacy/scheduleDB.data b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/schedulerDB/legacy/scheduleDB.data new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/schedulerDB/legacy/scheduleDB.redo b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/store/schedulerDB/legacy/scheduleDB.redo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/streams/JMSInputStreamTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/streams/JMSInputStreamTest.java new file mode 100644 index 0000000000..f3926628f1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/streams/JMSInputStreamTest.java @@ -0,0 +1,281 @@ +/** + * 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.streams; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQInputStream; +import org.apache.activemq.ActiveMQOutputStream; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +/** + * JMSInputStreamTest + */ +@Deprecated +public class JMSInputStreamTest extends JmsTestSupport { + + public Destination destination; + protected DataOutputStream out; + protected DataInputStream in; + private ActiveMQConnection connection2; + + private ActiveMQInputStream amqIn; + private ActiveMQOutputStream amqOut; + + public static Test suite() { + return suite(JMSInputStreamTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void initCombos() { + addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST.QUEUE"), new ActiveMQTopic("TEST.TOPIC") }); + } + + @Override + protected void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + } + + private void setUpConnection(Map props, long timeout) throws JMSException { + connection2 = (ActiveMQConnection) factory.createConnection(userName, password); + connections.add(connection2); + if (props != null) { + amqOut = (ActiveMQOutputStream) connection.createOutputStream(destination, props, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + } else { + amqOut = (ActiveMQOutputStream) connection.createOutputStream(destination); + } + + out = new DataOutputStream(amqOut); + if (timeout == -1) { + amqIn = (ActiveMQInputStream) connection2.createInputStream(destination); + } else { + amqIn = (ActiveMQInputStream) connection2.createInputStream(destination, null, false, timeout); + } + in = new DataInputStream(amqIn); + } + + /* + * @see TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Test for AMQ-3010 + */ + public void testInputStreamTimeout() throws Exception { + long timeout = 500; + + setUpConnection(null, timeout); + try { + in.read(); + fail(); + } catch (ActiveMQInputStream.ReadTimeoutException e) { + // timeout reached, everything ok + } + in.close(); + } + + // Test for AMQ-2988 + public void testStreamsWithProperties() throws Exception { + String name1 = "PROPERTY_1"; + String name2 = "PROPERTY_2"; + String value1 = "VALUE_1"; + String value2 = "VALUE_2"; + Map jmsProperties = new HashMap(); + jmsProperties.put(name1, value1); + jmsProperties.put(name2, value2); + setUpConnection(jmsProperties, -1); + + out.writeInt(4); + out.flush(); + assertTrue(in.readInt() == 4); + out.writeFloat(2.3f); + out.flush(); + assertTrue(in.readFloat() == 2.3f); + String str = "this is a test string"; + out.writeUTF(str); + out.flush(); + assertTrue(in.readUTF().equals(str)); + for (int i = 0; i < 100; i++) { + out.writeLong(i); + } + out.flush(); + + // check properties before we try to read the stream + checkProperties(jmsProperties); + + for (int i = 0; i < 100; i++) { + assertTrue(in.readLong() == i); + } + + // check again after read was done + checkProperties(jmsProperties); + } + + public void testStreamsWithPropertiesOnlyOnFirstMessage() throws Exception { + String name1 = "PROPERTY_1"; + String name2 = "PROPERTY_2"; + String value1 = "VALUE_1"; + String value2 = "VALUE_2"; + Map jmsProperties = new HashMap(); + jmsProperties.put(name1, value1); + jmsProperties.put(name2, value2); + + ActiveMQDestination dest = (ActiveMQDestination) destination; + + if (dest.isQueue()) { + destination = new ActiveMQQueue(dest.getPhysicalName() + "?producer.addPropertiesOnFirstMsgOnly=true"); + } else { + destination = new ActiveMQTopic(dest.getPhysicalName() + "?producer.addPropertiesOnFirstMsgOnly=true"); + } + + setUpConnection(jmsProperties, -1); + + assertTrue(amqOut.isAddPropertiesOnFirstMsgOnly()); + + out.writeInt(4); + out.flush(); + assertTrue(in.readInt() == 4); + out.writeFloat(2.3f); + out.flush(); + assertTrue(in.readFloat() == 2.3f); + String str = "this is a test string"; + out.writeUTF(str); + out.flush(); + assertTrue(in.readUTF().equals(str)); + for (int i = 0; i < 100; i++) { + out.writeLong(i); + } + out.flush(); + + // check properties before we try to read the stream + checkProperties(jmsProperties); + + for (int i = 0; i < 100; i++) { + assertTrue(in.readLong() == i); + } + + // check again after read was done + checkProperties(jmsProperties); + } + + // check if the received stream has the properties set + // Test for AMQ-2988 + private void checkProperties(Map jmsProperties) throws IOException { + Map receivedJmsProps = amqIn.getJMSProperties(); + + // we should at least have the same amount or more properties + assertTrue(jmsProperties.size() <= receivedJmsProps.size()); + + // check the properties to see if we have everything in there + Iterator propsIt = jmsProperties.keySet().iterator(); + while (propsIt.hasNext()) { + String key = propsIt.next(); + assertTrue(receivedJmsProps.containsKey(key)); + assertEquals(jmsProperties.get(key), receivedJmsProps.get(key)); + } + } + + public void testLarge() throws Exception { + setUpConnection(null, -1); + + final int testData = 23; + final int dataLength = 4096; + final int count = 1024; + byte[] data = new byte[dataLength]; + for (int i = 0; i < data.length; i++) { + data[i] = testData; + } + final AtomicBoolean complete = new AtomicBoolean(false); + Thread runner = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int x = 0; x < count; x++) { + byte[] b = new byte[2048]; + in.readFully(b); + for (int i = 0; i < b.length; i++) { + assertTrue(b[i] == testData); + } + } + complete.set(true); + synchronized (complete) { + complete.notify(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + runner.start(); + for (int i = 0; i < count; i++) { + out.write(data); + } + out.flush(); + synchronized (complete) { + if (!complete.get()) { + complete.wait(30000); + } + } + assertTrue(complete.get()); + } + + public void testStreams() throws Exception { + setUpConnection(null, -1); + out.writeInt(4); + out.flush(); + assertTrue(in.readInt() == 4); + out.writeFloat(2.3f); + out.flush(); + assertTrue(in.readFloat() == 2.3f); + String str = "this is a test string"; + out.writeUTF(str); + out.flush(); + assertTrue(in.readUTF().equals(str)); + for (int i = 0; i < 100; i++) { + out.writeLong(i); + } + out.flush(); + + for (int i = 0; i < 100; i++) { + assertTrue(in.readLong() == i); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsSendReceiveTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsSendReceiveTestSupport.java new file mode 100644 index 0000000000..931beedc9b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsSendReceiveTestSupport.java @@ -0,0 +1,260 @@ +/** + * 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.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.AssertionFailedError; + +import org.apache.activemq.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public abstract class JmsSendReceiveTestSupport extends org.apache.activemq.TestSupport implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(JmsSendReceiveTestSupport.class); + + protected int messageCount = 100; + protected String[] data; + protected Session session; + protected Session consumeSession; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected Destination consumerDestination; + protected Destination producerDestination; + protected List messages = createConcurrentList(); + protected boolean topic = true; + protected boolean durable; + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected final Object lock = new Object(); + protected boolean verbose; + protected boolean useSeparateSession; + protected boolean largeMessages; + protected int largeMessageLoopSize = 4 * 1024; + + /* + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + String temp = System.getProperty("messageCount"); + + if (temp != null) { + int i = Integer.parseInt(temp); + if (i > 0) { + messageCount = i; + } + } + + LOG.info("Message count for test case is: " + messageCount); + data = new String[messageCount]; + for (int i = 0; i < messageCount; i++) { + data[i] = createMessageText(i); + } + } + + protected String createMessageText(int i) { + if (largeMessages) { + return createMessageBodyText(); + } else { + return "Text for message: " + i + " at " + new Date(); + } + } + + protected String createMessageBodyText() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < largeMessageLoopSize; i++) { + buffer.append("0123456789"); + } + return buffer.toString(); + } + + /** + * Test if all the messages sent are being received. + * + * @throws Exception + */ + public void testSendReceive() throws Exception { + + Thread.sleep(1000); + messages.clear(); + + sendMessages(); + + assertMessagesAreReceived(); + LOG.info("" + data.length + " messages(s) received, closing down connections"); + } + + protected void sendMessages() throws Exception { + for (int i = 0; i < data.length; i++) { + Message message = createMessage(i); + configureMessage(message); + if (verbose) { + LOG.info("About to send a message: " + message + " with text: " + data[i]); + } + sendMessage(i, message); + } + } + + protected void sendMessage(int index, Message message) throws Exception { + System.out.println("----sending a message to dest: " + producerDestination); + producer.send(producerDestination, message); + } + + protected Message createMessage(int index) throws JMSException { + Message message = session.createTextMessage(data[index]); + return message; + } + + /** + * A hook to allow the message to be configured such as adding extra headers + * + * @throws JMSException + */ + protected void configureMessage(Message message) throws JMSException { + } + + /** + * Waits to receive the messages and performs the test if all messages have + * been received and are in sequential order. + * + * @throws JMSException + */ + protected void assertMessagesAreReceived() throws JMSException { + waitForMessagesToBeDelivered(); + assertMessagesReceivedAreValid(messages); + } + + /** + * Tests if the messages have all been received and are in sequential order. + * + * @param receivedMessages + * @throws JMSException + */ + protected void assertMessagesReceivedAreValid(List receivedMessages) throws JMSException { + List copyOfMessages = Arrays.asList(receivedMessages.toArray()); + int counter = 0; + + if (data.length != copyOfMessages.size()) { + for (Iterator iter = copyOfMessages.iterator(); iter.hasNext();) { + Object message = iter.next(); + LOG.info("<== " + counter++ + " = " + message); + } + } + + assertEquals("Invalid number of messages received", data.length, receivedMessages.size()); + + for (int i = 0; i < data.length; i++) { + Message received = receivedMessages.get(i); + try { + assertMessageValid(i, received); + } catch (AssertionFailedError e) { + for (int j = 0; j < data.length; j++) { + Message m = receivedMessages.get(j); + System.out.println(j+" => "+m.getJMSMessageID()); + } + throw e; + } + } + } + + protected void assertMessageValid(int index, Message message) throws JMSException { + TextMessage textMessage = (TextMessage)message; + String text = textMessage.getText(); + + if (verbose) { + LOG.info("Received Text: " + text); + } + + assertEquals("Message: " + index, data[index], text); + } + + /** + * Waits for the messages to be delivered or when the wait time has been + * reached. + */ + protected void waitForMessagesToBeDelivered() { + long maxWaitTime = 60000; + long waitTime = maxWaitTime; + long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); + + synchronized (lock) { + while (messages.size() < data.length && waitTime >= 0) { + try { + lock.wait(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + waitTime = maxWaitTime - (System.currentTimeMillis() - start); + } + } + } + + /** + * @see javax.jms.MessageListener#onMessage(javax.jms.Message) + */ + public synchronized void onMessage(Message message) { + consumeMessage(message, messages); + } + + /** + * Consumes a received message. + * + * @param message - a newly received message. + * @param messageList - list containing the received messages. + */ + protected void consumeMessage(Message message, List messageList) { + if (verbose) { + LOG.info("Received message: " + message); + } + + messageList.add(message); + + if (messageList.size() >= data.length) { + synchronized (lock) { + lock.notifyAll(); + } + } + } + + /** + * Creates a synchronized list. + * + * @return a synchronized view of the specified list. + */ + protected List createConcurrentList() { + return Collections.synchronizedList(new ArrayList()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveTest.java new file mode 100644 index 0000000000..84cedeae3b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveTest.java @@ -0,0 +1,119 @@ +/** + * 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.test; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsTopicSendReceiveTest extends JmsSendReceiveTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(JmsTopicSendReceiveTest.class); + + protected Connection connection; + + protected void setUp() throws Exception { + super.setUp(); + + connectionFactory = createConnectionFactory(); + connection = createConnection(); + if (durable) { + connection.setClientID(getClass().getName()); + } + + LOG.info("Created connection: " + connection); + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumeSession = createConsumerSession(); + + LOG.info("Created session: " + session); + LOG.info("Created consumeSession: " + consumeSession); + producer = session.createProducer(null); + producer.setDeliveryMode(deliveryMode); + + LOG.info("Created producer: " + producer + " delivery mode = " + (deliveryMode == DeliveryMode.PERSISTENT ? "PERSISTENT" : "NON_PERSISTENT")); + + if (topic) { + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + } else { + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + } + + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + consumerDestination.getClass()); + LOG.info("Created producer destination: " + producerDestination + " of type: " + producerDestination.getClass()); + consumer = createConsumer(); + consumer.setMessageListener(this); + startConnection(); + + LOG.info("Created connection: " + connection); + } + + protected void startConnection() throws JMSException { + connection.start(); + } + + protected void tearDown() throws Exception { + LOG.info("Dumping stats..."); + // TODO + // connectionFactory.getFactoryStats().dump(new IndentPrinter()); + + LOG.info("Closing down connection"); + + /** TODO we should be able to shut down properly */ + session.close(); + connection.close(); + } + + /** + * Creates a session. + * + * @return session + * @throws JMSException + */ + protected Session createConsumerSession() throws JMSException { + if (useSeparateSession) { + return connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } else { + return session; + } + } + + /** + * Creates a durable suscriber or a consumer. + * + * @return MessageConsumer - durable suscriber or consumer. + * @throws JMSException + */ + protected MessageConsumer createConsumer() throws JMSException { + if (durable) { + LOG.info("Creating durable consumer"); + return consumeSession.createDurableSubscriber((Topic)consumerDestination, getName()); + } + System.out.println(">>>>>>>creating cons on " + consumerDestination); + return consumeSession.createConsumer(consumerDestination); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithEmbeddedBrokerAndUserIDTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithEmbeddedBrokerAndUserIDTest.java new file mode 100644 index 0000000000..aac150f023 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithEmbeddedBrokerAndUserIDTest.java @@ -0,0 +1,111 @@ +/** + * 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.test; + +import java.util.List; + +import javax.jms.JMSException; +import javax.jms.Message; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsTopicSendReceiveWithEmbeddedBrokerAndUserIDTest extends JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest { + private static final Logger LOG = LoggerFactory.getLogger(JmsTopicSendReceiveWithEmbeddedBrokerAndUserIDTest.class); + + protected String userName = "James"; + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory answer = super.createConnectionFactory(); + answer.setUserName(userName); + return answer; + } + + @Override + protected void configureBroker(BrokerService answer) throws Exception { + answer.setPopulateJMSXUserID(true); + super.configureBroker(answer); + } + + @Override + protected void assertMessagesReceivedAreValid(List receivedMessages) throws JMSException { + super.assertMessagesReceivedAreValid(receivedMessages); + + // lets assert that the user ID is set + for (Message message : receivedMessages) { + String userID = message.getStringProperty("JMSXUserID"); + LOG.info("Received message with userID: " + userID); + assertEquals("JMSXUserID header", userName, userID); + } + } + + protected void assertMessagesAreReceived2() throws JMSException { + waitForMessagesToBeDelivered(); + assertMessagesReceivedAreValid2(messages); + } + + protected void assertMessagesReceivedAreValid2(List receivedMessages) throws JMSException { + super.assertMessagesReceivedAreValid(receivedMessages); + + // lets assert that the user ID is set + for (Message message : receivedMessages) { + String userID = (String) message.getObjectProperty("JMSXUserID"); + LOG.info("Received message with userID: " + userID); + assertEquals("JMSXUserID header", userName, userID); + } + } + + public void testSpoofedJMSXUserIdIsIgnored() throws Exception { + Thread.sleep(1000); + messages.clear(); + + for (int i = 0; i < data.length; i++) { + Message message = createMessage(i); + configureMessage(message); + message.setStringProperty("JMSXUserID", "spoofedId"); + if (verbose) { + LOG.info("About to send a message: " + message + " with text: " + data[i]); + } + sendMessage(i, message); + } + assertMessagesAreReceived(); + LOG.info("" + data.length + " messages(s) received, closing down connections"); + } + + public void testSpoofedJMSXUserIdIsIgnoredAsObjectProperty() throws Exception { + Thread.sleep(1000); + messages.clear(); + + for (int i = 0; i < data.length; i++) { + Message message = createMessage(i); + configureMessage(message); + message.setStringProperty("JMSXUserID", "spoofedId"); + if (verbose) { + LOG.info("About to send a message: " + message + " with text: " + data[i]); + } + sendMessage(i, message); + } + assertMessagesAreReceived2(); + LOG.info("" + data.length + " messages(s) received, closing down connections"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsAndByteSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsAndByteSelectorTest.java new file mode 100644 index 0000000000..78a7f6f0e8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsAndByteSelectorTest.java @@ -0,0 +1,37 @@ +/** + * 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.test; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; + +/** + * + */ +public class JmsTopicSendReceiveWithTwoConnectionsAndByteSelectorTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + + + protected void configureMessage(Message message) throws JMSException { + message.setByteProperty("dummy", (byte) 33); + } + + protected MessageConsumer createConsumer() throws JMSException { + return receiveSession.createConsumer(consumerDestination, "dummy = 33", false); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest.java new file mode 100644 index 0000000000..6bd92df8b5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest.java @@ -0,0 +1,69 @@ +/** + * 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.test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; + +/** + * + */ +public class JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + + protected BrokerService broker; + protected String bindAddress = "tcp://localhost:61616"; + + /** + * Sets up a test where the producer and consumer have their own connection. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + + if (broker != null) { + broker.stop(); + } + } + + /** + * Factory method to create a new broker + * + * @throws Exception + */ + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + configureBroker(answer); + answer.start(); + return answer; + } + + protected void configureBroker(BrokerService answer) throws Exception { + answer.addConnector(bindAddress); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(bindAddress); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsTest.java new file mode 100644 index 0000000000..21a3575990 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/JmsTopicSendReceiveWithTwoConnectionsTest.java @@ -0,0 +1,133 @@ +/** + * 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.test; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class JmsTopicSendReceiveWithTwoConnectionsTest extends JmsSendReceiveTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(JmsTopicSendReceiveWithTwoConnectionsTest.class); + + protected Connection sendConnection; + protected Connection receiveConnection; + protected Session receiveSession; + + /** + * Sets up a test where the producer and consumer have their own connection. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + + connectionFactory = createConnectionFactory(); + + LOG.info("Creating send connection"); + sendConnection = createSendConnection(); + LOG.info("Starting send connection"); + sendConnection.start(); + + LOG.info("Creating receive connection"); + receiveConnection = createReceiveConnection(); + LOG.info("Starting receive connection"); + receiveConnection.start(); + + LOG.info("Created sendConnection: " + sendConnection); + LOG.info("Created receiveConnection: " + receiveConnection); + + session = sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + receiveSession = receiveConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + LOG.info("Created sendSession: " + session); + LOG.info("Created receiveSession: " + receiveSession); + + producer = session.createProducer(null); + producer.setDeliveryMode(deliveryMode); + + LOG.info("Created producer: " + producer + " delivery mode = " + (deliveryMode == DeliveryMode.PERSISTENT ? "PERSISTENT" : "NON_PERSISTENT")); + + if (topic) { + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + } else { + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + } + + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + consumerDestination.getClass()); + LOG.info("Created producer destination: " + producerDestination + " of type: " + producerDestination.getClass()); + + consumer = createConsumer(); + consumer.setMessageListener(this); + + LOG.info("Started connections"); + } + + protected MessageConsumer createConsumer() throws JMSException { + return receiveSession.createConsumer(consumerDestination); + } + + /* + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + session.close(); + receiveSession.close(); + sendConnection.close(); + receiveConnection.close(); + } + + /** + * Creates a connection. + * + * @return Connection + * @throws Exception + */ + protected Connection createReceiveConnection() throws Exception { + return createConnection(); + } + + /** + * Creates a connection. + * + * @return Connection + * @throws Exception + */ + protected Connection createSendConnection() throws Exception { + return createConnection(); + } + + /** + * Creates an ActiveMQConnectionFactory. + * + * @see org.apache.activemq.test.TestSupport#createConnectionFactory() + */ + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/TemporaryDestinationToFromNameTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/TemporaryDestinationToFromNameTest.java new file mode 100644 index 0000000000..4dc008859e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/TemporaryDestinationToFromNameTest.java @@ -0,0 +1,58 @@ +/** + * 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.test; + +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.activemq.EmbeddedBrokerAndConnectionTestSupport; +import org.apache.activemq.broker.jmx.PurgeTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TemporaryDestinationToFromNameTest extends EmbeddedBrokerAndConnectionTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(TemporaryDestinationToFromNameTest.class); + + public void testCreateTemporaryQueueThenCreateAQueueFromItsName() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue tempQueue = session.createTemporaryQueue(); + String name = tempQueue.getQueueName(); + LOG.info("Created queue named: " + name); + + Queue createdQueue = session.createQueue(name); + + assertEquals("created queue not equal to temporary queue", tempQueue, createdQueue); + } + + public void testCreateTemporaryTopicThenCreateATopicFromItsName() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Topic tempTopic = session.createTemporaryTopic(); + String name = tempTopic.getTopicName(); + LOG.info("Created topic named: " + name); + + Topic createdTopic = session.createTopic(name); + + assertEquals("created topic not equal to temporary topic", tempTopic, createdTopic); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/message/NestedMapAndListPropertyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/message/NestedMapAndListPropertyTest.java new file mode 100644 index 0000000000..bf83d0ae9e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/message/NestedMapAndListPropertyTest.java @@ -0,0 +1,95 @@ +/** + * 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.test.message; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jms.JMSException; +import javax.jms.Message; + +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tests that a Message can have nested Map and List properties attached. + * + */ +public class NestedMapAndListPropertyTest extends JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest { + + private static final Logger LOG = LoggerFactory.getLogger(NestedMapAndListPropertyTest.class); + + @Override + @SuppressWarnings("rawtypes") + protected void assertMessageValid(int index, Message message) throws JMSException { + Object value = message.getObjectProperty("textField"); + assertEquals("textField", data[index], value); + + Map map = (Map)message.getObjectProperty("mapField"); + assertNotNull(map); + assertEquals("mapField.a", "foo", map.get("a")); + assertEquals("mapField.b", new Integer(23), map.get("b")); + assertEquals("mapField.c", new Long(45), map.get("c")); + + value = map.get("d"); + assertTrue("mapField.d should be a Map", value instanceof Map); + map = (Map)value; + + assertEquals("mapField.d.x", "abc", map.get("x")); + value = map.get("y"); + assertTrue("mapField.d.y is a List", value instanceof List); + List list = (List)value; + LOG.debug("mapField.d.y: " + list); + assertEquals("listField.size", 3, list.size()); + + LOG.debug("Found map: " + map); + + list = (List)message.getObjectProperty("listField"); + LOG.debug("listField: " + list); + assertEquals("listField.size", 3, list.size()); + assertEquals("listField[0]", "a", list.get(0)); + assertEquals("listField[1]", "b", list.get(1)); + assertEquals("listField[2]", "c", list.get(2)); + assertEquals("JohnDoe", message.getStringProperty("JMSXUserID")); + } + + @Override + protected Message createMessage(int index) throws JMSException { + Message answer = session.createMessage(); + + answer.setStringProperty("textField", data[index]); + + Map grandChildMap = new HashMap(); + grandChildMap.put("x", "abc"); + grandChildMap.put("y", Arrays.asList(new Object[] {"a", "b", "c"})); + + Map nestedMap = new HashMap(); + nestedMap.put("a", "foo"); + nestedMap.put("b", new Integer(23)); + nestedMap.put("c", new Long(45)); + nestedMap.put("d", grandChildMap); + + answer.setObjectProperty("mapField", nestedMap); + answer.setObjectProperty("listField", Arrays.asList(new Object[] {"a", "b", "c"})); + answer.setStringProperty("JMSXUserID", "JohnDoe"); + + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/message/NestedMapMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/message/NestedMapMessageTest.java new file mode 100644 index 0000000000..f0131ce068 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/message/NestedMapMessageTest.java @@ -0,0 +1,98 @@ +/** + * 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.test.message; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; + +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class NestedMapMessageTest extends JmsTopicSendReceiveWithTwoConnectionsAndEmbeddedBrokerTest { + + private static final Logger LOG = LoggerFactory.getLogger(NestedMapMessageTest.class); + + @Override + @SuppressWarnings("rawtypes") + protected void assertMessageValid(int index, Message message) throws JMSException { + assertTrue("Should be a MapMessage: " + message, message instanceof MapMessage); + + MapMessage mapMessage = (MapMessage)message; + + Object value = mapMessage.getObject("textField"); + assertEquals("textField", data[index], value); + + Map map = (Map)mapMessage.getObject("mapField"); + assertNotNull(map); + assertEquals("mapField.a", "foo", map.get("a")); + assertEquals("mapField.b", Integer.valueOf(23), map.get("b")); + assertEquals("mapField.c", Long.valueOf(45), map.get("c")); + + value = map.get("d"); + assertTrue("mapField.d should be a Map", value instanceof Map); + map = (Map)value; + + assertEquals("mapField.d.x", "abc", map.get("x")); + value = map.get("y"); + assertTrue("mapField.d.y is a List", value instanceof List); + List list = (List)value; + LOG.debug("mapField.d.y: " + list); + assertEquals("listField.size", 3, list.size()); + + LOG.debug("Found map: " + map); + + list = (List)mapMessage.getObject("listField"); + LOG.debug("listField: " + list); + assertEquals("listField.size", 3, list.size()); + assertEquals("listField[0]", "a", list.get(0)); + assertEquals("listField[1]", "b", list.get(1)); + assertEquals("listField[2]", "c", list.get(2)); + } + + @Override + protected Message createMessage(int index) throws JMSException { + MapMessage answer = session.createMapMessage(); + + answer.setString("textField", data[index]); + + Map grandChildMap = new HashMap(); + grandChildMap.put("x", "abc"); + grandChildMap.put("y", Arrays.asList(new Object[] {"a", "b", "c"})); + + Map nestedMap = new HashMap(); + nestedMap.put("a", "foo"); + nestedMap.put("b", Integer.valueOf(23)); + nestedMap.put("c", Long.valueOf(45)); + nestedMap.put("d", grandChildMap); + + answer.setObject("mapField", nestedMap); + answer.setObject("listField", Arrays.asList(new Object[] {"a", "b", "c"})); + + return answer; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/DummyMessageQuery.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/DummyMessageQuery.java new file mode 100644 index 0000000000..98f547cc72 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/DummyMessageQuery.java @@ -0,0 +1,50 @@ +/** + * 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.test.retroactive; + +import javax.jms.MessageListener; + +import org.apache.activemq.broker.region.policy.MessageQuery; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.Message; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class DummyMessageQuery implements MessageQuery { + + public static final int MESSAGE_COUNT = 10; + private static final Logger LOG = LoggerFactory.getLogger(DummyMessageQuery.class); + + + public void execute(ActiveMQDestination destination, MessageListener listener) throws Exception { + LOG.info("Initial query is creating: " + MESSAGE_COUNT + " messages"); + for (int i = 0; i < MESSAGE_COUNT; i++) { + ActiveMQTextMessage message = new ActiveMQTextMessage(); + message.setText("Initial message: " + i + " loaded from query"); + listener.onMessage(message); + } + } + + public boolean validateUpdate(Message message) { + return true; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithDestinationBasedBufferTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithDestinationBasedBufferTest.java new file mode 100644 index 0000000000..0248109ac8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithDestinationBasedBufferTest.java @@ -0,0 +1,27 @@ +/** + * 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.test.retroactive; + +/** + * + * + */ +public class RetroactiveConsumerTestWithDestinationBasedBufferTest extends RetroactiveConsumerTestWithSimpleMessageListTest { + protected String getBrokerXml() { + return "org/apache/activemq/test/retroactive/activemq-fixed-destination-buffer.xml"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithLastImagePolicyWithWildcardTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithLastImagePolicyWithWildcardTest.java new file mode 100644 index 0000000000..d34189a735 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithLastImagePolicyWithWildcardTest.java @@ -0,0 +1,48 @@ +/** + * 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.test.retroactive; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; + +import org.apache.activemq.command.ActiveMQTopic; + +/** + * + */ +public class RetroactiveConsumerTestWithLastImagePolicyWithWildcardTest extends RetroactiveConsumerTestWithSimpleMessageListTest { + private int counter = 1; + + protected void sendMessage(MessageProducer producer, TextMessage message) throws JMSException { + ActiveMQTopic topic = new ActiveMQTopic(destination.getPhysicalName() + "." + (counter++)); + producer.send(topic, message); + } + + protected MessageProducer createProducer() throws JMSException { + return session.createProducer(null); + } + + protected MessageConsumer createConsumer() throws JMSException { + return session.createConsumer(new ActiveMQTopic(destination.getPhysicalName() + ".>")); + } + + protected String getBrokerXml() { + return "org/apache/activemq/test/retroactive/activemq-lastimage-policy.xml"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithSimpleMessageListTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithSimpleMessageListTest.java new file mode 100644 index 0000000000..ecc6bde940 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithSimpleMessageListTest.java @@ -0,0 +1,127 @@ +/** + * 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.test.retroactive; + +import java.net.URI; +import java.util.Date; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class RetroactiveConsumerTestWithSimpleMessageListTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(RetroactiveConsumerTestWithSimpleMessageListTest.class); + + protected int messageCount = 20; + protected Connection connection; + protected Session session; + + public void testSendThenConsume() throws Exception { + + // lets some messages + connection = createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = createProducer(); + for (int i = 0; i < messageCount; i++) { + TextMessage message = session.createTextMessage("Message: " + i + " sent at: " + new Date()); + sendMessage(producer, message); + } + producer.close(); + session.close(); + connection.close(); + + connection = createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = createConsumer(); + MessageIdList listener = new MessageIdList(); + consumer.setMessageListener(listener); + listener.waitForMessagesToArrive(messageCount); + listener.assertMessagesReceived(messageCount); + + } + + @Override + protected void setUp() throws Exception { + useTopic = true; + bindAddress = "vm://localhost"; + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + if (session != null) { + session.close(); + session = null; + } + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory answer = new ActiveMQConnectionFactory(bindAddress); + answer.setUseRetroactiveConsumer(true); + return answer; + } + + @Override + protected BrokerService createBroker() throws Exception { + String uri = getBrokerXml(); + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + + @Override + protected void startBroker() throws Exception { + // broker already started by XBean + } + + protected String getBrokerXml() { + return "org/apache/activemq/test/retroactive/activemq-fixed-buffer.xml"; + } + + protected MessageProducer createProducer() throws JMSException { + return session.createProducer(destination); + } + + protected void sendMessage(MessageProducer producer, TextMessage message) throws JMSException { + producer.send(message); + } + + protected MessageConsumer createConsumer() throws JMSException { + return session.createConsumer(destination); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithTimePolicyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithTimePolicyTest.java new file mode 100644 index 0000000000..bb99b5d00a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerTestWithTimePolicyTest.java @@ -0,0 +1,27 @@ +/** + * 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.test.retroactive; + +/** + * + * + */ +public class RetroactiveConsumerTestWithTimePolicyTest extends RetroactiveConsumerTestWithSimpleMessageListTest { + protected String getBrokerXml() { + return "org/apache/activemq/test/retroactive/activemq-timed-policy.xml"; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerWithMessageQueryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerWithMessageQueryTest.java new file mode 100644 index 0000000000..2631619644 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/RetroactiveConsumerWithMessageQueryTest.java @@ -0,0 +1,114 @@ +/** + * 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.test.retroactive; + +import java.net.URI; +import java.util.Date; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class RetroactiveConsumerWithMessageQueryTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(RetroactiveConsumerWithMessageQueryTest.class); + + protected int messageCount = 20; + protected Connection connection; + protected Session session; + + public void testConsumeAndReceiveInitialQueryBeforeUpdates() throws Exception { + + // lets some messages + connection = createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.start(); + + MessageConsumer consumer = session.createConsumer(destination); + MessageIdList listener = new MessageIdList(); + listener.setVerbose(true); + consumer.setMessageListener(listener); + + MessageProducer producer = session.createProducer(destination); + int updateMessageCount = messageCount - DummyMessageQuery.MESSAGE_COUNT; + for (int i = 0; i < updateMessageCount; i++) { + TextMessage message = session.createTextMessage("Update Message: " + i + " sent at: " + new Date()); + producer.send(message); + } + producer.close(); + LOG.info("Sent: " + updateMessageCount + " update messages"); + + listener.assertMessagesReceived(messageCount); + } + + @Override + protected void setUp() throws Exception { + useTopic = true; + bindAddress = "vm://localhost"; + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + if (session != null) { + session.close(); + session = null; + } + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + @Override + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory answer = new ActiveMQConnectionFactory(bindAddress); + // answer.setUseRetroactiveConsumer(true); + // option applied via destination policy alwaysRetroactive + return answer; + } + + @Override + protected BrokerService createBroker() throws Exception { + String uri = getBrokerXml(); + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + + @Override + protected void startBroker() throws Exception { + // broker already started by XBean + } + + protected String getBrokerXml() { + return "org/apache/activemq/test/retroactive/activemq-message-query.xml"; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-fixed-buffer.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-fixed-buffer.xml new file mode 100644 index 0000000000..820bdc0035 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-fixed-buffer.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-fixed-destination-buffer.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-fixed-destination-buffer.xml new file mode 100644 index 0000000000..45d623c65f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-fixed-destination-buffer.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-lastimage-policy.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-lastimage-policy.xml new file mode 100644 index 0000000000..0ee21a660b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-lastimage-policy.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-message-query.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-message-query.xml new file mode 100644 index 0000000000..7b10860534 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-message-query.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-timed-policy.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-timed-policy.xml new file mode 100644 index 0000000000..5e45fb3bc2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/retroactive/activemq-timed-policy.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/CloseRollbackRedeliveryQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/CloseRollbackRedeliveryQueueTest.java new file mode 100644 index 0000000000..26725a64f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/CloseRollbackRedeliveryQueueTest.java @@ -0,0 +1,134 @@ +/** + * 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.test.rollback; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jms.core.MessageCreator; + +public class CloseRollbackRedeliveryQueueTest extends EmbeddedBrokerTestSupport { + + private static final transient Logger LOG = LoggerFactory.getLogger(CloseRollbackRedeliveryQueueTest.class); + + protected int numberOfMessagesOnQueue = 1; + private Connection connection; + + public void testVerifySessionCloseRedeliveryWithFailoverTransport() throws Throwable { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(destination); + + Message message = consumer.receive(1000); + String id = message.getJMSMessageID(); + assertNotNull(message); + LOG.info("got message " + message); + // close will rollback the current tx + session.close(); + + session = connection.createSession(true, Session.SESSION_TRANSACTED); + consumer = session.createConsumer(destination); + + message = consumer.receive(1000); + session.commit(); + assertNotNull(message); + assertEquals("redelivered message", id, message.getJMSMessageID()); + assertEquals(2, message.getLongProperty("JMSXDeliveryCount")); + } + + public void testVerifyConsumerAndSessionCloseRedeliveryWithFailoverTransport() throws Throwable { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(destination); + + Message message = consumer.receive(1000); + String id = message.getJMSMessageID(); + assertNotNull(message); + LOG.info("got message " + message); + consumer.close(); + session.close(); + session = connection.createSession(true, Session.SESSION_TRANSACTED); + consumer = session.createConsumer(destination); + + message = consumer.receive(1000); + session.commit(); + assertNotNull(message); + assertEquals("redelivered message", id, message.getJMSMessageID()); + assertEquals(2, message.getLongProperty("JMSXDeliveryCount")); + } + + public void testVerifyConsumerCloseSessionRollbackRedeliveryWithFailoverTransport() throws Throwable { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(destination); + + Message message = consumer.receive(1000); + String id = message.getJMSMessageID(); + assertNotNull(message); + LOG.info("got message " + message); + consumer.close(); + session.rollback(); + + consumer = session.createConsumer(destination); + message = consumer.receive(1000); + session.commit(); + assertNotNull(message); + assertEquals("redelivered message", id, message.getJMSMessageID()); + assertEquals(2, message.getLongProperty("JMSXDeliveryCount")); + } + + protected void setUp() throws Exception { + super.setUp(); + + connection = createConnection(); + connection.start(); + + // lets fill the queue up + for (int i = 0; i < numberOfMessagesOnQueue; i++) { + template.send(createMessageCreator(i)); + } + + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + // failover: enables message audit - which could get in the way of redelivery + return new ActiveMQConnectionFactory("failover:" + bindAddress); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + protected MessageCreator createMessageCreator(final int i) { + return new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + TextMessage answer = session.createTextMessage("Message: " + i); + answer.setIntProperty("Counter", i); + return answer; + } + }; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/DelegatingTransactionalMessageListener.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/DelegatingTransactionalMessageListener.java new file mode 100644 index 0000000000..8fd3457a98 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/DelegatingTransactionalMessageListener.java @@ -0,0 +1,70 @@ +/** + * 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.test.rollback; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DelegatingTransactionalMessageListener implements MessageListener { + private static final transient Logger LOG = LoggerFactory.getLogger(DelegatingTransactionalMessageListener.class); + + private final MessageListener underlyingListener; + private boolean transacted = true; + private int ackMode = Session.AUTO_ACKNOWLEDGE; + private Session session; + + public DelegatingTransactionalMessageListener(MessageListener underlyingListener, Connection connection, Destination destination) { + this.underlyingListener = underlyingListener; + + try { + session = connection.createSession(transacted, ackMode); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(this); + } catch (JMSException e) { + throw new IllegalStateException("Could not listen to " + destination, e); + } + } + + public void onMessage(Message message) { + try { + underlyingListener.onMessage(message); + session.commit(); + } catch (Throwable e) { + rollback(); + } + } + + private void rollback() { + try { + session.rollback(); + } catch (JMSException e) { + LOG.error("Failed to rollback: " + e, e); + } + } + + public Session getSession() { + return session; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/RollbacksWhileConsumingLargeQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/RollbacksWhileConsumingLargeQueueTest.java new file mode 100644 index 0000000000..cebe74d5af --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/test/rollback/RollbacksWhileConsumingLargeQueueTest.java @@ -0,0 +1,182 @@ +/** + * 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.test.rollback; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.RedeliveryPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jms.core.MessageCreator; + +/** + * + */ +public class RollbacksWhileConsumingLargeQueueTest extends EmbeddedBrokerTestSupport implements MessageListener { + + private static final transient Logger LOG = LoggerFactory.getLogger(RollbacksWhileConsumingLargeQueueTest.class); + + protected int numberOfMessagesOnQueue = 650; + private Connection connection; + private AtomicInteger deliveryCounter = new AtomicInteger(0); + private AtomicInteger ackCounter = new AtomicInteger(0); + private CountDownLatch latch; + private Throwable failure; + + public void testWithReciever() throws Throwable { + latch = new CountDownLatch(numberOfMessagesOnQueue); + Session session = connection.createSession(true, 0); + MessageConsumer consumer = session.createConsumer(destination); + + long start = System.currentTimeMillis(); + while ((System.currentTimeMillis() - start) < 1000 * 1000) { + if (getFailure() != null) { + throw getFailure(); + } + + // Are we done receiving all the messages. + if (ackCounter.get() == numberOfMessagesOnQueue) { + return; + } + + Message message = consumer.receive(1000); + if (message == null) { + continue; + } + + try { + onMessage(message); + session.commit(); + } catch (Throwable e) { + session.rollback(); + } + } + + fail("Did not receive all the messages."); + } + + public void testWithMessageListener() throws Throwable { + latch = new CountDownLatch(numberOfMessagesOnQueue); + new DelegatingTransactionalMessageListener(this, connection, destination); + + long start = System.currentTimeMillis(); + while ((System.currentTimeMillis() - start) < 1000 * 1000) { + + if (getFailure() != null) { + throw getFailure(); + } + + if (latch.await(1, TimeUnit.SECONDS)) { + LOG.debug("Received: " + deliveryCounter.get() + " message(s)"); + return; + } + + } + + fail("Did not receive all the messages."); + } + + protected ConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory answer = (ActiveMQConnectionFactory) super.createConnectionFactory(); + RedeliveryPolicy policy = new RedeliveryPolicy(); + policy.setMaximumRedeliveries(3); + policy.setRedeliveryDelay(0); + policy.setInitialRedeliveryDelay(0); + policy.setUseExponentialBackOff(false); + answer.setRedeliveryPolicy(policy); + return answer; + } + + protected void setUp() throws Exception { + super.setUp(); + + connection = createConnection(); + connection.start(); + + // lets fill the queue up + for (int i = 0; i < numberOfMessagesOnQueue; i++) { + template.send(createMessageCreator(i)); + } + + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } + + protected MessageCreator createMessageCreator(final int i) { + return new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + TextMessage answer = session.createTextMessage("Message: " + i); + answer.setIntProperty("Counter", i); + return answer; + } + }; + } + + public void onMessage(Message message) { + String msgId = null; + String msgText = null; + + try { + msgId = message.getJMSMessageID(); + msgText = ((TextMessage)message).getText(); + } catch (JMSException e) { + setFailure(e); + } + + try { + assertEquals("Message: " + ackCounter.get(), msgText); + } catch (Throwable e) { + setFailure(e); + } + + int value = deliveryCounter.incrementAndGet(); + if (value % 2 == 0) { + LOG.info("Rolling Back message: " + ackCounter.get() + " id: " + msgId + ", content: " + msgText); + throw new RuntimeException("Dummy exception on message: " + value); + } + + LOG.info("Received message: " + ackCounter.get() + " id: " + msgId + ", content: " + msgText); + ackCounter.incrementAndGet(); + latch.countDown(); + } + + public synchronized Throwable getFailure() { + return failure; + } + + public synchronized void setFailure(Throwable failure) { + this.failure = failure; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/QueueClusterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/QueueClusterTest.java new file mode 100644 index 0000000000..447e2e2e87 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/QueueClusterTest.java @@ -0,0 +1,33 @@ +/** + * 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.transport; + +/** + * + */ +public class QueueClusterTest extends TopicClusterTest { + + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } + + protected int expectedReceiveCount() { + return MESSAGE_COUNT * NUMBER_IN_CLUSTER; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/SoWriteTimeoutClientTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/SoWriteTimeoutClientTest.java new file mode 100644 index 0000000000..59ba91501f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/SoWriteTimeoutClientTest.java @@ -0,0 +1,111 @@ +/** + * 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.transport; + +import java.net.URI; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.SocketProxy; +import org.apache.activemq.util.URISupport; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SoWriteTimeoutClientTest extends JmsTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(SoWriteTimeoutClientTest.class); + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + KahaDBPersistenceAdapter adapter = new KahaDBPersistenceAdapter(); + adapter.setConcurrentStoreAndDispatchQueues(false); + broker.setPersistenceAdapter(adapter); + broker.addConnector("tcp://localhost:0?wireFormat.maxInactivityDuration=0"); + return broker; + } + + public void testSendWithClientWriteTimeout() throws Exception { + final ActiveMQQueue dest = new ActiveMQQueue("testClientWriteTimeout"); + messageTextPrefix = initMessagePrefix(80*1024); + + URI tcpBrokerUri = URISupport.removeQuery(broker.getTransportConnectors().get(0).getConnectUri()); + LOG.info("consuming using uri: " + tcpBrokerUri); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(tcpBrokerUri); + Connection c = factory.createConnection(); + c.start(); + Session session = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(dest); + + SocketProxy proxy = new SocketProxy(); + proxy.setTarget(tcpBrokerUri); + proxy.open(); + + ActiveMQConnectionFactory pFactory = new ActiveMQConnectionFactory("failover:(" + proxy.getUrl() + "?soWriteTimeout=4000&sleep=500)?jms.useAsyncSend=true&trackMessages=true&maxCacheSize=6638400"); + final Connection pc = pFactory.createConnection(); + pc.start(); + proxy.pause(); + + final int messageCount = 20; + ExecutorService executorService = Executors.newCachedThreadPool(); + executorService.execute(new Runnable() { + @Override + public void run() { + try{ + sendMessages(pc, dest, messageCount); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + }); + + // wait for timeout and reconnect + TimeUnit.SECONDS.sleep(8); + proxy.goOn(); + for (int i=0; i transportURIs = new ArrayList(); + + /** + * @see org.apache.activemq.transport.CompositeTransport#add(java.net.URI[]) + */ + public void add(boolean rebalance, URI[] uris) + { + transportURIs.addAll(Arrays.asList(uris)); + } + + /** + * @see org.apache.activemq.transport.CompositeTransport#remove(java.net.URI[]) + */ + public void remove(boolean rebalance, URI[] uris) + { + transportURIs.removeAll(Arrays.asList(uris)); + } + + public URI[] getTransportURIs() + { + return transportURIs.toArray(new URI[0]); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/StubTransport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/StubTransport.java new file mode 100644 index 0000000000..8fb70ec966 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/StubTransport.java @@ -0,0 +1,57 @@ +/** + * 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.transport; + +import java.io.IOException; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.apache.activemq.util.ServiceStopper; + +/** + * + * + */ +public class StubTransport extends TransportSupport { + + private Queue queue = new ConcurrentLinkedQueue(); + private volatile int receiveCounter; + + protected void doStop(ServiceStopper stopper) throws Exception { + } + + protected void doStart() throws Exception { + } + + public void oneway(Object command) throws IOException { + receiveCounter++; + queue.add(command); + } + + public Queue getQueue() { + return queue; + } + + public String getRemoteAddress() { + return null; + } + + public int getReceiveCounter() { + return receiveCounter; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/StubTransportListener.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/StubTransportListener.java new file mode 100644 index 0000000000..018cfc7925 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/StubTransportListener.java @@ -0,0 +1,58 @@ +/** + * 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.transport; + +import java.io.IOException; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * + * + */ +public class StubTransportListener implements TransportListener { + + private final Queue commands = new ConcurrentLinkedQueue(); + private final Queue exceptions = new ConcurrentLinkedQueue(); + + public Queue getCommands() { + return commands; + } + + public Queue getExceptions() { + return exceptions; + } + + @Override + public void onCommand(Object command) { + commands.add(command); + } + + @Override + public void onException(IOException error) { + exceptions.add(error); + } + + @Override + public void transportInterupted() { + } + + @Override + public void transportResumed() { + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/TopicClusterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/TopicClusterTest.java new file mode 100644 index 0000000000..4db7c239c8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/TopicClusterTest.java @@ -0,0 +1,179 @@ +/** + * 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.transport; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +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.command.ActiveMQTextMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.ServiceStopper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TopicClusterTest extends TestCase implements MessageListener { + + protected static final int MESSAGE_COUNT = 50; + protected static final int NUMBER_IN_CLUSTER = 3; + private static final Logger LOG = LoggerFactory.getLogger(TopicClusterTest.class); + + protected Destination destination; + protected boolean topic = true; + protected AtomicInteger receivedMessageCount = new AtomicInteger(0); + protected int deliveryMode = DeliveryMode.NON_PERSISTENT; + protected MessageProducer[] producers; + protected Connection[] connections; + protected List services = new ArrayList(); + protected String groupId; + + protected void setUp() throws Exception { + groupId = "topic-cluster-test-"+System.currentTimeMillis(); + connections = new Connection[NUMBER_IN_CLUSTER]; + producers = new MessageProducer[NUMBER_IN_CLUSTER]; + Destination destination = createDestination(); + String root = System.getProperty("activemq.store.dir"); + if (root == null) { + root = "target/store"; + } + try { + for (int i = 0; i < NUMBER_IN_CLUSTER; i++) { + + System.setProperty("activemq.store.dir", root + "_broker_" + i); + connections[i] = createConnection("broker-" + i); + connections[i].setClientID("ClusterTest" + i); + connections[i].start(); + Session session = connections[i].createSession(false, Session.AUTO_ACKNOWLEDGE); + producers[i] = session.createProducer(destination); + producers[i].setDeliveryMode(deliveryMode); + MessageConsumer consumer = createMessageConsumer(session, destination); + consumer.setMessageListener(this); + + } + LOG.info("Sleeping to ensure cluster is fully connected"); + Thread.sleep(5000); + } finally { + System.setProperty("activemq.store.dir", root); + } + } + + protected void tearDown() throws Exception { + if (connections != null) { + for (int i = 0; i < connections.length; i++) { + connections[i].close(); + } + } + ServiceStopper stopper = new ServiceStopper(); + stopper.stopServices(services); + } + + protected MessageConsumer createMessageConsumer(Session session, Destination destination) throws JMSException { + return session.createConsumer(destination); + } + + protected ActiveMQConnectionFactory createGenericClusterFactory(String brokerName) throws Exception { + BrokerService container = new BrokerService(); + container.setBrokerName(brokerName); + + String url = "tcp://localhost:0"; + TransportConnector connector = container.addConnector(url); + connector.setDiscoveryUri(new URI("multicast://default?group="+groupId)); + container.addNetworkConnector("multicast://default?group="+groupId); + container.start(); + + services.add(container); + + return new ActiveMQConnectionFactory("vm://" + brokerName); + } + + protected int expectedReceiveCount() { + return MESSAGE_COUNT * NUMBER_IN_CLUSTER * NUMBER_IN_CLUSTER; + } + + protected Connection createConnection(String name) throws Exception { + return createGenericClusterFactory(name).createConnection(); + } + + protected Destination createDestination() { + return createDestination(getClass().getName()); + } + + protected Destination createDestination(String name) { + if (topic) { + return new ActiveMQTopic(name); + } else { + return new ActiveMQQueue(name); + } + } + + /** + * @param msg + */ + public void onMessage(Message msg) { + // log.info("GOT: " + msg); + receivedMessageCount.incrementAndGet(); + synchronized (receivedMessageCount) { + if (receivedMessageCount.get() >= expectedReceiveCount()) { + receivedMessageCount.notify(); + } + } + } + + /** + * @throws Exception + */ + public void testSendReceive() throws Exception { + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage textMessage = new ActiveMQTextMessage(); + textMessage.setText("MSG-NO:" + i); + for (int x = 0; x < producers.length; x++) { + producers[x].send(textMessage); + } + } + synchronized (receivedMessageCount) { + if (receivedMessageCount.get() < expectedReceiveCount()) { + receivedMessageCount.wait(20000); + } + } + // sleep a little - to check we don't get too many messages + Thread.sleep(2000); + LOG.info("GOT: " + receivedMessageCount.get()); + assertEquals("Expected message count not correct", expectedReceiveCount(), receivedMessageCount.get()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/TransportBrokerTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/TransportBrokerTestSupport.java new file mode 100644 index 0000000000..5c221d330c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/TransportBrokerTestSupport.java @@ -0,0 +1,78 @@ +/** + * 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.transport; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.BrokerTest; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.TransportConnector; + +public abstract class TransportBrokerTestSupport extends BrokerTest { + + protected TransportConnector connector; + private ArrayList connections = new ArrayList(); + + protected void setUp() throws Exception { + super.setUp(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService service = super.createBroker(); + connector = service.addConnector(getBindLocation()); + return service; + } + + protected abstract String getBindLocation(); + + protected void tearDown() throws Exception { + for (Iterator iter = connections.iterator(); iter.hasNext();) { + StubConnection connection = iter.next(); + connection.stop(); + iter.remove(); + } + if( connector!=null ) { + connector.stop(); + } + super.tearDown(); + } + + protected URI getBindURI() throws URISyntaxException { + return new URI(getBindLocation()); + } + + protected StubConnection createConnection() throws Exception { + URI bindURI = getBindURI(); + + // Note: on platforms like OS X we cannot bind to the actual hostname, so we + // instead use the original host name (typically localhost) to bind to + + URI actualURI = connector.getServer().getConnectURI(); + URI connectURI = new URI(actualURI.getScheme(), actualURI.getUserInfo(), bindURI.getHost(), actualURI.getPort(), actualURI.getPath(), bindURI + .getQuery(), bindURI.getFragment()); + + Transport transport = TransportFactory.connect(connectURI); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryNetworkReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryNetworkReconnectTest.java new file mode 100644 index 0000000000..8601c34268 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryNetworkReconnectTest.java @@ -0,0 +1,240 @@ +/** + * 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.transport.discovery; + +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.transport.discovery.multicast.MulticastDiscoveryAgentFactory; +import org.apache.activemq.util.SocketProxy; +import org.apache.activemq.util.Wait; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.jmock.api.Invocation; +import org.jmock.integration.junit4.JMock; +import org.jmock.integration.junit4.JUnit4Mockery; +import org.jmock.lib.action.CustomAction; +import org.jmock.lib.legacy.ClassImposteriser; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +@RunWith(JMock.class) +public class DiscoveryNetworkReconnectTest { + + private static final Logger LOG = LoggerFactory.getLogger(DiscoveryNetworkReconnectTest.class); + final int maxReconnects = 2; + final String groupName = "GroupID-" + "DiscoveryNetworkReconnectTest"; + final String discoveryAddress = "multicast://default?group=" + groupName + "&initialReconnectDelay=1000"; + final Semaphore mbeanRegistered = new Semaphore(0); + final Semaphore mbeanUnregistered = new Semaphore(0); + BrokerService brokerA, brokerB; + Mockery context; + ManagementContext managementContext; + DiscoveryAgent agent; + SocketProxy proxy; + + // ignore the hostname resolution component as this is machine dependent + class NetworkBridgeObjectNameMatcher extends BaseMatcher { + T name; + NetworkBridgeObjectNameMatcher(T o) { + name = o; + } + + @Override + public boolean matches(Object arg0) { + ObjectName other = (ObjectName) arg0; + ObjectName mine = (ObjectName) name; + LOG.info("Match: " + mine + " vs: " + other); + + if (!"networkConnectors".equals(other.getKeyProperty("connector"))) { + return false; + } + return other.getKeyProperty("connector").equals(mine.getKeyProperty("connector")) && + other.getKeyProperty("networkBridge") != null && mine.getKeyProperty("networkBridge") != null; + } + + @Override + public void describeTo(Description arg0) { + arg0.appendText(this.getClass().getName()); + } + } + + @Before + public void setUp() throws Exception { + context = new JUnit4Mockery() {{ + setImposteriser(ClassImposteriser.INSTANCE); + }}; + brokerA = new BrokerService(); + brokerA.setBrokerName("BrokerA"); + configure(brokerA); + brokerA.addConnector("tcp://localhost:0"); + brokerA.start(); + brokerA.waitUntilStarted(); + + proxy = new SocketProxy(brokerA.getTransportConnectors().get(0).getConnectUri()); + managementContext = context.mock(ManagementContext.class); + + context.checking(new Expectations(){{ + allowing(managementContext).getJmxDomainName(); will (returnValue("Test")); + allowing(managementContext).setBrokerName("BrokerNC"); + allowing(managementContext).start(); + allowing(managementContext).isCreateConnector(); + allowing(managementContext).stop(); + allowing(managementContext).isConnectorStarted(); + + // expected MBeans + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC")))); + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,service=Health")))); + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,connector=networkConnectors,networkConnectorName=NC")))); + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,service=Log4JConfiguration")))); + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,destinationType=Topic,destinationName=ActiveMQ.Advisory.Connection")))); + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,destinationType=Topic,destinationName=ActiveMQ.Advisory.NetworkBridge")))); + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,destinationType=Topic,destinationName=ActiveMQ.Advisory.MasterBroker")))); + allowing(managementContext).registerMBean(with(any(Object.class)), with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,service=jobScheduler,jobSchedulerName=JMS")))); + + atLeast(maxReconnects - 1).of (managementContext).registerMBean(with(any(Object.class)), with(new NetworkBridgeObjectNameMatcher( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,connector=networkConnectors,networkConnectorName=NC,networkBridge=localhost/127.0.0.1_" + + proxy.getUrl().getPort())))); will(new CustomAction("signal register network mbean") { + @Override + public Object invoke(Invocation invocation) throws Throwable { + LOG.info("Mbean Registered: " + invocation.getParameter(0)); + mbeanRegistered.release(); + return new ObjectInstance((ObjectName)invocation.getParameter(1), "discription"); + } + }); + atLeast(maxReconnects - 1).of (managementContext).unregisterMBean(with(new NetworkBridgeObjectNameMatcher( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,connector=networkConnectors,networkConnectorName=NC,networkBridge=localhost/127.0.0.1_" + + proxy.getUrl().getPort())))); will(new CustomAction("signal unregister network mbean") { + @Override + public Object invoke(Invocation invocation) throws Throwable { + LOG.info("Mbean Unregistered: " + invocation.getParameter(0)); + mbeanUnregistered.release(); + return null; + } + }); + + allowing(managementContext).unregisterMBean(with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC")))); + allowing(managementContext).unregisterMBean(with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,service=Health")))); + allowing(managementContext).unregisterMBean(with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,connector=networkConnectors,networkConnectorName=NC")))); + allowing(managementContext).unregisterMBean(with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,service=Log4JConfiguration")))); + allowing(managementContext).unregisterMBean(with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,destinationType=Topic,destinationName=ActiveMQ.Advisory.Connection")))); + allowing(managementContext).unregisterMBean(with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,destinationType=Topic,destinationName=ActiveMQ.Advisory.NetworkBridge")))); + allowing(managementContext).unregisterMBean(with(equal( + new ObjectName("Test:type=Broker,brokerName=BrokerNC,destinationType=Topic,destinationName=ActiveMQ.Advisory.MasterBroker")))); + }}); + + brokerB = new BrokerService(); + brokerB.setManagementContext(managementContext); + brokerB.setBrokerName("BrokerNC"); + configure(brokerB); + } + + @After + public void tearDown() throws Exception { + brokerA.stop(); + brokerA.waitUntilStopped(); + brokerB.stop(); + brokerB.waitUntilStopped(); + proxy.close(); + } + + private void configure(BrokerService broker) { + broker.setPersistent(false); + broker.setUseJmx(true); + } + + @Test + public void testMulicastReconnect() throws Exception { + + brokerB.addNetworkConnector(discoveryAddress + "&discovered.trace=true&discovered.wireFormat.maxInactivityDuration=1000&discovered.wireFormat.maxInactivityDurationInitalDelay=1000"); + brokerB.start(); + brokerB.waitUntilStarted(); + + // control multicast advertise agent to inject proxy + agent = MulticastDiscoveryAgentFactory.createDiscoveryAgent(new URI(discoveryAddress)); + agent.registerService(proxy.getUrl().toString()); + agent.start(); + + doReconnect(); + } + + @Test + public void testSimpleReconnect() throws Exception { + brokerB.addNetworkConnector("simple://(" + proxy.getUrl() + + ")?useExponentialBackOff=false&initialReconnectDelay=500&discovered.wireFormat.maxInactivityDuration=1000&discovered.wireFormat.maxInactivityDurationInitalDelay=1000"); + brokerB.start(); + brokerB.waitUntilStarted(); + doReconnect(); + } + + private void doReconnect() throws Exception { + + for (int i=0; i= 1; + } + })); + + // wait for network connector + assertTrue("network connector mbean registered within 1 minute", mbeanRegistered.tryAcquire(60, TimeUnit.SECONDS)); + + // force an inactivity timeout via the proxy + proxy.pause(); + + // wait for the inactivity timeout and network shutdown + assertTrue("network connector mbean unregistered within 1 minute", mbeanUnregistered.tryAcquire(60, TimeUnit.SECONDS)); + + // whack all connections + proxy.close(); + + // let a reconnect succeed + proxy.reopen(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryTransportBrokerTest.java new file mode 100644 index 0000000000..2f77109d8b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryTransportBrokerTest.java @@ -0,0 +1,162 @@ +/** + * 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.transport.discovery; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; + +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.network.NetworkTestSupport; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.failover.FailoverTransport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DiscoveryTransportBrokerTest extends NetworkTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(DiscoveryTransportBrokerTest.class); + + String groupName; + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + } + + public void testPublisherFailsOver() throws Exception { + ActiveMQDestination destination = new ActiveMQQueue("TEST"); + int deliveryMode = DeliveryMode.NON_PERSISTENT; + + // Start a normal consumer on the local broker + StubConnection connection1 = createConnection(); + ConnectionInfo connectionInfo1 = createConnectionInfo(); + SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + 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); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + // Start a failover publisher. + StubConnection connection3 = createFailoverConnection(); + ConnectionInfo connectionInfo3 = createConnectionInfo(); + SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); + ProducerInfo producerInfo3 = createProducerInfo(sessionInfo3); + connection3.send(connectionInfo3); + connection3.send(sessionInfo3); + connection3.send(producerInfo3); + + // Send the message using the fail over publisher. + connection3.request(createMessage(producerInfo3, destination, deliveryMode)); + + // The message will be sent to one of the brokers. + FailoverTransport ft = (FailoverTransport)connection3.getTransport().narrow(FailoverTransport.class); + + // See which broker we were connected to. + StubConnection connectionA; + StubConnection connectionB; + TransportConnector serverA; + if (connector.getServer().getConnectURI().getPort() == ft.getConnectedTransportURI().getPort()) { + connectionA = connection1; + connectionB = connection2; + serverA = connector; + } else { + connectionA = connection2; + connectionB = connection1; + serverA = remoteConnector; + } + + assertNotNull(receiveMessage(connectionA)); + assertNoMessagesLeft(connectionB); + + // Dispose the server so that it fails over to the other server. + LOG.info("Disconnecting active server"); + serverA.stop(); + + LOG.info("Sending request that should failover"); + connection3.request(createMessage(producerInfo3, destination, deliveryMode)); + + assertNotNull(receiveMessage(connectionB)); + assertNoMessagesLeft(connectionA); + + } + + protected String getLocalURI() { + return "tcp://localhost:0?wireFormat.tcpNoDelayEnabled=true"; + } + + protected String getRemoteURI() { + return "tcp://localhost:0?wireFormat.tcpNoDelayEnabled=true"; + } + + protected TransportConnector createConnector() throws Exception, IOException, URISyntaxException { + TransportConnector x = super.createConnector(); + x.setDiscoveryUri(new URI(getDiscoveryUri())); + return x; + } + + protected String getDiscoveryUri() { + if ( groupName == null ) { + groupName = "group-"+System.currentTimeMillis(); + } + return "multicast://default?group="+groupName; + } + + protected TransportConnector createRemoteConnector() throws Exception, IOException, URISyntaxException { + TransportConnector x = super.createRemoteConnector(); + x.setDiscoveryUri(new URI(getDiscoveryUri())); + return x; + } + + protected StubConnection createFailoverConnection() throws Exception { + URI failoverURI = new URI("discovery:(" + getDiscoveryUri() + ")?startupMaxReconnectAttempts=10&initialReconnectDelay=1000"); + Transport transport = TransportFactory.connect(failoverURI); + StubConnection connection = new StubConnection(transport); + connections.add(connection); + return connection; + } + + public static Test suite() { + return suite(DiscoveryTransportBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryTransportNoBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryTransportNoBrokerTest.java new file mode 100644 index 0000000000..7ba24db55f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryTransportNoBrokerTest.java @@ -0,0 +1,179 @@ +/** + * 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.transport.discovery; + +import java.net.URI; +import java.util.Map; +import java.util.Vector; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.DiscoveryEvent; +import org.apache.activemq.transport.StubCompositeTransport; +import org.apache.activemq.util.URISupport; +import org.apache.activemq.util.URISupport.CompositeData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DiscoveryTransportNoBrokerTest extends CombinationTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(DiscoveryTransportNoBrokerTest.class); + + @Override + public void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + } + + public void testNoExtraThreads() throws Exception { + BrokerService broker = new BrokerService(); + TransportConnector tcp = broker.addConnector("tcp://localhost:0?transport.closeAsync=false"); + String group = "GR-" + System.currentTimeMillis(); + URI discoveryUri = new URI("multicast://default?group=" + group); + tcp.setDiscoveryUri(discoveryUri); + broker.start(); + broker.waitUntilStarted(); + + Vector existingNames = new Vector(); + Thread[] threads = getThreads(); + for (Thread t : threads) { + existingNames.add(t.getName()); + } + final int idleThreadCount = threads.length; + LOG.info("Broker started - thread Count:" + idleThreadCount); + + final int noConnectionToCreate = 10; + for (int i=0; i<10;i++) { + ActiveMQConnectionFactory factory = + new ActiveMQConnectionFactory("discovery:(multicast://239.255.2.3:6155?group=" + group +")?closeAsync=false&startupMaxReconnectAttempts=10&initialReconnectDelay=1000"); + LOG.info("Connecting."); + Connection connection = factory.createConnection(); + connection.setClientID("test"); + connection.close(); + } + Thread.sleep(2000); + threads = getThreads(); + for (Thread t : threads) { + if (!existingNames.contains(t.getName())) { + LOG.info("Remaining thread:" + t); + } + } + assertTrue("no extra threads per connection", Thread.activeCount() - idleThreadCount < noConnectionToCreate); + } + + + private Thread[] getThreads() { + Thread[] threads = new Thread[Thread.activeCount()]; + Thread.enumerate(threads); + return threads; + } + + + public void testMaxReconnectAttempts() throws JMSException { + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("discovery:(multicast://doesNOTexist)"); + LOG.info("Connecting."); + Connection connection = factory.createConnection(); + connection.setClientID("test"); + fail("Did not fail to connect as expected."); + } + catch ( JMSException expected ) { + assertTrue("reason is java.io.IOException, was: " + expected.getCause(), expected.getCause() instanceof java.io.IOException); + } + } + + public void testInitialConnectDelayWithNoBroker() throws Exception { + // the initialReconnectDelay only kicks in once a set of connect URL have + // been returned from the discovery agent. + // Up to that point the reconnectDelay is used which has a default value of 10 + // + long initialReconnectDelay = 4000; + long startT = System.currentTimeMillis(); + String groupId = "WillNotMatch" + startT; + try { + String urlStr = "discovery:(multicast://default?group=" + groupId + + ")?useExponentialBackOff=false&maxReconnectAttempts=2&reconnectDelay=" + initialReconnectDelay; + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(urlStr); + LOG.info("Connecting."); + Connection connection = factory.createConnection(); + connection.setClientID("test"); + fail("Did not fail to connect as expected."); + } catch ( JMSException expected ) { + assertTrue("reason is java.io.IOException, was: " + expected.getCause(), expected.getCause() instanceof java.io.IOException); + long duration = System.currentTimeMillis() - startT; + assertTrue("took at least initialReconnectDelay time: " + duration + " e:" + expected, duration >= initialReconnectDelay); + } + } + + public void testSetDiscoveredBrokerProperties() throws Exception { + final String extraParameterName = "connectionTimeout"; + final String extraParameterValue = "3000"; + final URI uri = new URI("discovery:(multicast://default)?initialReconnectDelay=100&" + + DiscoveryListener.DISCOVERED_OPTION_PREFIX + extraParameterName + "=" + extraParameterValue); + CompositeData compositeData = URISupport.parseComposite(uri); + + StubCompositeTransport compositeTransport = new StubCompositeTransport(); + DiscoveryTransport discoveryTransport = DiscoveryTransportFactory.createTransport(compositeTransport, compositeData, compositeData.getParameters()); + + discoveryTransport.onServiceAdd(new DiscoveryEvent("tcp://localhost:61616")); + assertEquals("expected added URI after discovery event", compositeTransport.getTransportURIs().length, 1); + + URI discoveredServiceURI = compositeTransport.getTransportURIs()[0]; + Map parameters = URISupport.parseParameters(discoveredServiceURI); + assertTrue("unable to add parameter to discovered service", parameters.containsKey(extraParameterName)); + assertEquals("incorrect value for parameter added to discovered service", parameters.get(extraParameterName), extraParameterValue); + } + + public void testSetDiscoveredStaticBrokerProperties() throws Exception { + final String extraParameterName = "connectionTimeout"; + final String extraParameterValue = "3000"; + final URI uri = new URI("discovery:(static:tcp://localhost:61616)?initialReconnectDelay=100&" + + DiscoveryListener.DISCOVERED_OPTION_PREFIX + extraParameterName + "=" + extraParameterValue); + CompositeData compositeData = URISupport.parseComposite(uri); + + StubCompositeTransport compositeTransport = new StubCompositeTransport(); + DiscoveryTransport discoveryTransport = DiscoveryTransportFactory.createTransport(compositeTransport, compositeData, compositeData.getParameters()); + + discoveryTransport.start(); + assertEquals("expected added URI after discovery event", 1, compositeTransport.getTransportURIs().length); + + URI discoveredServiceURI = compositeTransport.getTransportURIs()[0]; + Map parameters = URISupport.parseParameters(discoveredServiceURI); + assertTrue("unable to add parameter to discovered service", parameters.containsKey(extraParameterName)); + assertEquals("incorrect value for parameter added to discovered service", parameters.get(extraParameterName), extraParameterValue); + } + + public void testAddRemoveDiscoveredBroker() throws Exception { + final URI uri = new URI("discovery:(multicast://default)?initialReconnectDelay=100&connectionTimeout=3000"); + CompositeData compositeData = URISupport.parseComposite(uri); + + StubCompositeTransport compositeTransport = new StubCompositeTransport(); + DiscoveryTransport discoveryTransport = DiscoveryTransportFactory.createTransport(compositeTransport, compositeData, compositeData.getParameters()); + + final String serviceName = "tcp://localhost:61616"; + discoveryTransport.onServiceAdd(new DiscoveryEvent(serviceName)); + assertEquals("expected added URI after discovery event", 1, compositeTransport.getTransportURIs().length); + + discoveryTransport.onServiceRemove(new DiscoveryEvent(serviceName)); + assertEquals("expected URI removed after discovery event", 0, compositeTransport.getTransportURIs().length); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryUriTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryUriTest.java new file mode 100644 index 0000000000..778d03d9f0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/DiscoveryUriTest.java @@ -0,0 +1,65 @@ +/** + * 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.transport.discovery; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; + +import javax.jms.*; +import java.net.URI; + +public class DiscoveryUriTest extends EmbeddedBrokerTestSupport { + + @Override + protected BrokerService createBroker() throws Exception { + bindAddress = "tcp://localhost:0"; + BrokerService answer = new BrokerService(); + answer.setPersistent(isPersistent()); + TransportConnector connector = new TransportConnector(); + connector.setUri(new URI(bindAddress)); + connector.setDiscoveryUri(new URI("multicast://default?group=test")); + answer.addConnector(connector); + return answer; + } + + public void testConnect() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("discovery:(multicast://default?group=test)?reconnectDelay=1000&maxReconnectAttempts=30&useExponentialBackOff=false"); + Connection conn = factory.createConnection(); + conn.start(); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = sess.createProducer(sess.createQueue("test")); + producer.send(sess.createTextMessage("test")); + MessageConsumer consumer = sess.createConsumer(sess.createQueue("test")); + Message msg = consumer.receive(1000); + assertNotNull(msg); + } + + public void testFailedConnect() throws Exception { + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("discovery:(multicast://default?group=test1)?reconnectDelay=1000&startupMaxReconnectAttempts=3&useExponentialBackOff=false"); + Connection conn = factory.createConnection(); + conn.start(); + } catch (Exception e) { + return; + } + fail("Expected connection failure"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/ZeroconfDiscoverTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/ZeroconfDiscoverTransportTest.java new file mode 100644 index 0000000000..92614107d6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/discovery/ZeroconfDiscoverTransportTest.java @@ -0,0 +1,29 @@ +/** + * 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.transport.discovery; + +/** + * + * + */ +public class ZeroconfDiscoverTransportTest extends DiscoveryTransportBrokerTest { + + protected String getDiscoveryUri() { + return "zeroconf://cheese"; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/AMQ1925Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/AMQ1925Test.java new file mode 100644 index 0000000000..dfb5dfde47 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/AMQ1925Test.java @@ -0,0 +1,408 @@ +/** + * 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.transport.failover; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TransactionRolledBackException; + +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.broker.region.Queue; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.ServiceStopper; +import org.apache.log4j.Logger; + +/** + * TestCase showing the message-destroying described in AMQ-1925 + * + * + */ +public class AMQ1925Test extends TestCase implements ExceptionListener { + private static final Logger log = Logger.getLogger(AMQ1925Test.class); + + private static final String QUEUE_NAME = "test.amq1925"; + private static final String PROPERTY_MSG_NUMBER = "NUMBER"; + private static final int MESSAGE_COUNT = 10000; + + private BrokerService bs; + private URI tcpUri; + private ActiveMQConnectionFactory cf; + + private JMSException exception; + + public void XtestAMQ1925_TXInProgress() throws Exception { + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(true, + Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(session + .createQueue(QUEUE_NAME)); + + // The runnable is likely to interrupt during the session#commit, since + // this takes the longest + final Object starter = new Object(); + final AtomicBoolean restarted = new AtomicBoolean(); + new Thread(new Runnable() { + public void run() { + try { + synchronized (starter) { + starter.wait(); + } + + // Simulate broker failure & restart + bs.stop(); + bs = new BrokerService(); + bs.setPersistent(true); + bs.setUseJmx(true); + bs.addConnector(tcpUri); + bs.start(); + + restarted.set(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + + synchronized (starter) { + starter.notifyAll(); + } + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message message = consumer.receive(500); + assertNotNull("No Message " + i + " found", message); + + if (i < 10) + assertFalse("Timing problem, restarted too soon", restarted + .get()); + if (i == 10) { + synchronized (starter) { + starter.notifyAll(); + } + } + if (i > MESSAGE_COUNT - 100) { + assertTrue("Timing problem, restarted too late", restarted + .get()); + } + + assertEquals(i, message.getIntProperty(PROPERTY_MSG_NUMBER)); + session.commit(); + } + assertNull(consumer.receive(500)); + + consumer.close(); + session.close(); + connection.close(); + + assertQueueEmpty(); + } + + public void XtestAMQ1925_TXInProgress_TwoConsumers() throws Exception { + Connection connection = cf.createConnection(); + connection.start(); + Session session1 = connection.createSession(true, + Session.SESSION_TRANSACTED); + MessageConsumer consumer1 = session1.createConsumer(session1 + .createQueue(QUEUE_NAME)); + Session session2 = connection.createSession(true, + Session.SESSION_TRANSACTED); + MessageConsumer consumer2 = session2.createConsumer(session2 + .createQueue(QUEUE_NAME)); + + // The runnable is likely to interrupt during the session#commit, since + // this takes the longest + final Object starter = new Object(); + final AtomicBoolean restarted = new AtomicBoolean(); + new Thread(new Runnable() { + public void run() { + try { + synchronized (starter) { + starter.wait(); + } + + // Simulate broker failure & restart + bs.stop(); + bs = new BrokerService(); + bs.setPersistent(true); + bs.setUseJmx(true); + bs.addConnector(tcpUri); + bs.start(); + + restarted.set(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + + synchronized (starter) { + starter.notifyAll(); + } + Collection results = new ArrayList(MESSAGE_COUNT); + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message message1 = consumer1.receive(20); + Message message2 = consumer2.receive(20); + if (message1 == null && message2 == null) { + if (results.size() < MESSAGE_COUNT) { + message1 = consumer1.receive(500); + message2 = consumer2.receive(500); + + if (message1 == null && message2 == null) { + // Missing messages + break; + } + } + break; + } + + if (i < 10) + assertFalse("Timing problem, restarted too soon", restarted + .get()); + if (i == 10) { + synchronized (starter) { + starter.notifyAll(); + } + } + if (i > MESSAGE_COUNT - 50) { + assertTrue("Timing problem, restarted too late", restarted + .get()); + } + + if (message1 != null) { + results.add(message1.getIntProperty(PROPERTY_MSG_NUMBER)); + session1.commit(); + } + if (message2 != null) { + results.add(message2.getIntProperty(PROPERTY_MSG_NUMBER)); + session2.commit(); + } + } + assertNull(consumer1.receive(500)); + assertNull(consumer2.receive(500)); + + consumer1.close(); + session1.close(); + consumer2.close(); + session2.close(); + connection.close(); + + int foundMissingMessages = 0; + if (results.size() < MESSAGE_COUNT) { + foundMissingMessages = tryToFetchMissingMessages(); + } + for (int i = 0; i < MESSAGE_COUNT; i++) { + assertTrue("Message-Nr " + i + " not found (" + results.size() + + " total, " + foundMissingMessages + + " have been found 'lingering' in the queue)", results + .contains(i)); + } + assertQueueEmpty(); + } + + private int tryToFetchMissingMessages() throws JMSException { + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(true, 0); + MessageConsumer consumer = session.createConsumer(session + .createQueue(QUEUE_NAME)); + + int count = 0; + while (true) { + Message message = consumer.receive(500); + if (message == null) + break; + + log.info("Found \"missing\" message: " + message); + count++; + } + + consumer.close(); + session.close(); + connection.close(); + + return count; + } + + public void testAMQ1925_TXBegin() throws Exception { + Connection connection = cf.createConnection(); + connection.start(); + connection.setExceptionListener(this); + Session session = connection.createSession(true, + Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(session + .createQueue(QUEUE_NAME)); + + boolean restartDone = false; + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message message = consumer.receive(5000); + assertNotNull(message); + + if (i == 222 && !restartDone) { + // Simulate broker failure & restart + bs.stop(); + bs = new BrokerService(); + bs.setPersistent(true); + bs.setUseJmx(true); + bs.addConnector(tcpUri); + bs.start(); + restartDone = true; + } + + assertEquals(i, message.getIntProperty(PROPERTY_MSG_NUMBER)); + try { + session.commit(); + } catch (TransactionRolledBackException expectedOnOccasion) { + log.info("got rollback: " + expectedOnOccasion); + i--; + } + } + assertNull(consumer.receive(500)); + + consumer.close(); + session.close(); + connection.close(); + + assertQueueEmpty(); + assertNull("no exception on connection listener: " + exception, exception); + } + + public void testAMQ1925_TXCommited() throws Exception { + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(true, + Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(session + .createQueue(QUEUE_NAME)); + + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message message = consumer.receive(5000); + assertNotNull(message); + + assertEquals(i, message.getIntProperty(PROPERTY_MSG_NUMBER)); + session.commit(); + + if (i == 222) { + // Simulate broker failure & restart + bs.stop(); + bs = new BrokerService(); + bs.setPersistent(true); + bs.setUseJmx(true); + bs.addConnector(tcpUri); + bs.start(); + } + } + assertNull(consumer.receive(500)); + + consumer.close(); + session.close(); + connection.close(); + + assertQueueEmpty(); + } + + private void assertQueueEmpty() throws Exception { + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(true, + Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(session + .createQueue(QUEUE_NAME)); + + Message msg = consumer.receive(500); + if (msg != null) { + fail(msg.toString()); + } + + consumer.close(); + session.close(); + connection.close(); + + assertQueueLength(0); + } + + private void assertQueueLength(int len) throws Exception, IOException { + Set destinations = bs.getBroker().getDestinations( + new ActiveMQQueue(QUEUE_NAME)); + Queue queue = (Queue) destinations.iterator().next(); + assertEquals(len, queue.getMessageStore().getMessageCount()); + } + + private void sendMessagesToQueue() throws Exception { + Connection connection = cf.createConnection(); + Session session = connection.createSession(true, + Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(session + .createQueue(QUEUE_NAME)); + + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + for (int i = 0; i < MESSAGE_COUNT; i++) { + TextMessage message = session + .createTextMessage("Test message " + i); + message.setIntProperty(PROPERTY_MSG_NUMBER, i); + producer.send(message); + } + session.commit(); + + producer.close(); + session.close(); + connection.close(); + + assertQueueLength(MESSAGE_COUNT); + } + + protected void setUp() throws Exception { + exception = null; + bs = new BrokerService(); + bs.setDeleteAllMessagesOnStartup(true); + bs.setPersistent(true); + bs.setUseJmx(true); + TransportConnector connector = bs.addConnector("tcp://localhost:0"); + bs.start(); + tcpUri = connector.getConnectUri(); + + cf = new ActiveMQConnectionFactory("failover://(" + tcpUri + ")"); + + sendMessagesToQueue(); + } + + protected void tearDown() throws Exception { + new ServiceStopper().stop(bs); + } + + public void onException(JMSException exception) { + this.exception = exception; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/BadConnectionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/BadConnectionTest.java new file mode 100644 index 0000000000..dd89456e87 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/BadConnectionTest.java @@ -0,0 +1,77 @@ +/** + * 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.transport.failover; + +import java.io.IOException; +import java.net.URI; + +import junit.framework.TestCase; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class BadConnectionTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(BadConnectionTest.class); + + protected Transport transport; + + public void testConnectingToUnavailableServer() throws Exception { + try { + transport.asyncRequest(new ActiveMQMessage(), null); + fail("This should never succeed"); + } catch (IOException e) { + LOG.info("Caught expected exception: " + e, e); + } + } + + protected Transport createTransport() throws Exception { + return TransportFactory.connect(new URI("failover://(tcp://doesNotExist:1234)?useExponentialBackOff=false&maxReconnectAttempts=3&initialReconnectDelay=100")); + } + + protected void setUp() throws Exception { + transport = createTransport(); + transport.setTransportListener(new TransportListener() { + + public void onCommand(Object command) { + } + + public void onException(IOException error) { + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + transport.start(); + } + + protected void tearDown() throws Exception { + if (transport != null) { + transport.stop(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/ConnectionHangOnStartupTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/ConnectionHangOnStartupTest.java new file mode 100644 index 0000000000..09e496e943 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/ConnectionHangOnStartupTest.java @@ -0,0 +1,110 @@ +/** + * 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.transport.failover; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Connection; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +/** + * Tests for AMQ-3719 + */ +public class ConnectionHangOnStartupTest { + + private static final Logger LOG = LoggerFactory.getLogger(ConnectionHangOnStartupTest.class); + + // short maxInactivityDurationInitalDelay to trigger the bug, short + // maxReconnectDelay so that the test runs faster (because it will retry + // connection sooner) + protected String uriString = "failover://(tcp://localhost:62001?wireFormat.maxInactivityDurationInitalDelay=1,tcp://localhost:62002?wireFormat.maxInactivityDurationInitalDelay=1)?randomize=false&maxReconnectDelay=200"; + protected BrokerService master = null; + protected AtomicReference slave = new AtomicReference(); + + @After + public void tearDown() throws Exception { + + BrokerService brokerService = slave.get(); + if (brokerService != null) { + brokerService.stop(); + } + if (master != null) + master.stop(); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(uriString); + } + + protected void createMaster() throws Exception { + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(new ClassPathResource(getMasterXml())); + brokerFactory.afterPropertiesSet(); + master = brokerFactory.getBroker(); + master.start(); + } + + protected void createSlave() throws Exception { + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(new ClassPathResource(getSlaveXml())); + brokerFactory.afterPropertiesSet(); + BrokerService broker = brokerFactory.getBroker(); + broker.start(); + slave.set(broker); + } + + protected String getSlaveXml() { + return "org/apache/activemq/broker/ft/sharedFileSlave.xml"; + } + + protected String getMasterXml() { + return "org/apache/activemq/broker/ft/sharedFileMaster.xml"; + } + + @Test(timeout=60000) + public void testInitialWireFormatNegotiationTimeout() throws Exception { + final AtomicReference conn = new AtomicReference(); + final CountDownLatch connStarted = new CountDownLatch(1); + + Thread t = new Thread() { + @Override + public void run() { + try { + conn.set(createConnectionFactory().createConnection()); + conn.get().start(); + } catch (Exception ex) { + LOG.error("could not create or start connection", ex); + } + connStarted.countDown(); + } + }; + t.start(); + createMaster(); + // slave will never start unless the master dies! + //createSlave(); + + conn.get().stop(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverBackupLeakTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverBackupLeakTest.java new file mode 100644 index 0000000000..24278be1d8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverBackupLeakTest.java @@ -0,0 +1,127 @@ +/** + * 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.transport.failover; + +import static org.junit.Assert.assertTrue; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Ensures connections aren't leaked when when we use backup=true and randomize=false + */ +public class FailoverBackupLeakTest { + + private static BrokerService s1, s2; + + @BeforeClass + public static void setUp() throws Exception { + s1 = buildBroker("broker1"); + s2 = buildBroker("broker2"); + + s1.start(); + s1.waitUntilStarted(); + s2.start(); + s2.waitUntilStarted(); + } + + @AfterClass + public static void tearDown() throws Exception { + if (s2 != null) { + s2.stop(); + s2.waitUntilStopped(); + } + if (s1 != null) { + s1.stop(); + s1.waitUntilStopped(); + } + } + + private static String getConnectString(BrokerService service) throws Exception { + return service.getTransportConnectors().get(0).getPublishableConnectString(); + } + + private static BrokerService buildBroker(String brokerName) throws Exception { + BrokerService service = new BrokerService(); + service.setBrokerName(brokerName); + service.setUseJmx(false); + service.setPersistent(false); + service.setUseShutdownHook(false); + service.addConnector("tcp://0.0.0.0:0?transport.closeAsync=false"); + return service; + } + + @Test + public void backupNoRandomize() throws Exception { + check("backup=true&randomize=false"); + } + + @Test + public void priorityBackupNoRandomize() throws Exception { + check("priorityBackup=true&randomize=false"); + } + + private void check(String connectionProperties) throws Exception { + String s1URL = getConnectString(s1), s2URL = getConnectString(s2); + String uri = "failover://(" + s1URL + "," + s2URL + ")?" + connectionProperties; + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(uri); + for (int i = 0; i < 10; i++) { + buildConnection(factory); + } + + assertTrue(connectionProperties + " broker1 connection count not zero: was["+getConnectionCount(s1)+"]", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return getConnectionCount(s1) == 0; + } + })); + + assertTrue(connectionProperties + " broker2 connection count not zero: was["+getConnectionCount(s2)+"]", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return getConnectionCount(s2) == 0; + } + })); + } + + private int getConnectionCount(BrokerService service) { + return service.getTransportConnectors().get(0).getConnections().size(); + } + + private void buildConnection(ConnectionFactory local) throws JMSException { + Connection conn = null; + Session sess = null; + try { + conn = local.createConnection(); + sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + } finally { + try { if (sess != null) sess.close(); } catch (JMSException ignore) { } + try { if (conn != null) conn.close(); } catch (JMSException ignore) { } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTest.java new file mode 100644 index 0000000000..417516f03d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTest.java @@ -0,0 +1,163 @@ +/** + * 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.transport.failover; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.NetworkConnector; + +public class FailoverClusterTest extends TestCase { + + private static final int NUMBER = 10; + private static final String BROKER_BIND_ADDRESS = "tcp://0.0.0.0:0"; + private static final String BROKER_A_NAME = "BROKERA"; + private static final String BROKER_B_NAME = "BROKERB"; + private BrokerService brokerA; + private BrokerService brokerB; + private String clientUrl; + + private final List connections = new ArrayList(); + + public void testClusterConnectedAfterClients() throws Exception { + createClients(); + if (brokerB == null) { + brokerB = createBrokerB(BROKER_BIND_ADDRESS); + } + Thread.sleep(3000); + Set set = new HashSet(); + for (ActiveMQConnection c : connections) { + set.add(c.getTransportChannel().getRemoteAddress()); + } + assertTrue(set.size() > 1); + } + + public void testClusterURIOptionsStrip() throws Exception { + createClients(); + if (brokerB == null) { + // add in server side only url param, should not be propagated + brokerB = createBrokerB(BROKER_BIND_ADDRESS + "?transport.closeAsync=false"); + } + Thread.sleep(3000); + Set set = new HashSet(); + for (ActiveMQConnection c : connections) { + set.add(c.getTransportChannel().getRemoteAddress()); + } + assertTrue(set.size() > 1); + } + + public void testClusterConnectedBeforeClients() throws Exception { + + if (brokerB == null) { + brokerB = createBrokerB(BROKER_BIND_ADDRESS); + } + Thread.sleep(5000); + createClients(); + Thread.sleep(2000); + brokerA.stop(); + Thread.sleep(2000); + + URI brokerBURI = new URI( brokerB.getTransportConnectors().get(0).getPublishableConnectString()); + for (ActiveMQConnection c : connections) { + String addr = c.getTransportChannel().getRemoteAddress(); + assertTrue(addr.indexOf("" + brokerBURI.getPort()) > 0); + } + } + + @Override + protected void setUp() throws Exception { + if (brokerA == null) { + brokerA = createBrokerA(BROKER_BIND_ADDRESS + "?transport.closeAsync=false"); + clientUrl = "failover://(" + brokerA.getTransportConnectors().get(0).getPublishableConnectString() + ")"; + } + } + + @Override + protected void tearDown() throws Exception { + for (Connection c : connections) { + c.close(); + } + if (brokerB != null) { + brokerB.stop(); + brokerB = null; + } + if (brokerA != null) { + brokerA.stop(); + brokerA = null; + } + } + + protected BrokerService createBrokerA(String uri) throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseJmx(false); + configureConsumerBroker(answer, uri); + answer.start(); + return answer; + } + + protected void configureConsumerBroker(BrokerService answer, String uri) throws Exception { + answer.setBrokerName(BROKER_A_NAME); + answer.setPersistent(false); + TransportConnector connector = answer.addConnector(uri); + connector.setRebalanceClusterClients(true); + connector.setUpdateClusterClients(true); + answer.setUseShutdownHook(false); + } + + protected BrokerService createBrokerB(String uri) throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseJmx(false); + configureNetwork(answer, uri); + answer.start(); + return answer; + } + + protected void configureNetwork(BrokerService answer, String uri) throws Exception { + answer.setBrokerName(BROKER_B_NAME); + answer.setPersistent(false); + NetworkConnector network = answer.addNetworkConnector("static://" + brokerA.getTransportConnectors().get(0).getPublishableConnectString()); + network.setDuplex(true); + TransportConnector connector = answer.addConnector(uri); + connector.setRebalanceClusterClients(true); + connector.setUpdateClusterClients(true); + answer.setUseShutdownHook(false); + } + + @SuppressWarnings("unused") + protected void createClients() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(clientUrl); + for (int i = 0; i < NUMBER; i++) { + ActiveMQConnection c = (ActiveMQConnection) factory.createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + connections.add(c); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTestSupport.java new file mode 100644 index 0000000000..b277636851 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTestSupport.java @@ -0,0 +1,202 @@ +/** + * 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.transport.failover; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.NetworkConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FailoverClusterTestSupport extends TestCase { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private static final int NUMBER_OF_CLIENTS = 30; + + private String clientUrl; + + private final Map brokers = new HashMap(); + private final List connections = new ArrayList(); + + protected void assertClientsConnectedToTwoBrokers() { + Set set = new HashSet(); + for (ActiveMQConnection c : connections) { + if (c.getTransportChannel().getRemoteAddress() != null) { + set.add(c.getTransportChannel().getRemoteAddress()); + } + } + assertTrue("Only 2 connections should be found: " + set, + set.size() == 2); + } + + protected void assertClientsConnectedToThreeBrokers() { + Set set = new HashSet(); + for (ActiveMQConnection c : connections) { + if (c.getTransportChannel().getRemoteAddress() != null) { + set.add(c.getTransportChannel().getRemoteAddress()); + } + } + assertTrue("Only 3 connections should be found: " + set, + set.size() == 3); + } + + protected void assertClientsConnectionsEvenlyDistributed(double minimumPercentage) { + Map clientConnectionCounts = new HashMap(); + int total = 0; + for (ActiveMQConnection c : connections) { + String key = c.getTransportChannel().getRemoteAddress(); + if (key != null) { + total++; + if (clientConnectionCounts.containsKey(key)) { + double count = clientConnectionCounts.get(key); + count += 1.0; + clientConnectionCounts.put(key, count); + } else { + clientConnectionCounts.put(key, 1.0); + } + } + } + Set keys = clientConnectionCounts.keySet(); + for(String key: keys){ + double count = clientConnectionCounts.get(key); + double percentage = count / total; + logger.info(count + " of " + total + " connections for " + key + " = " + percentage); + assertTrue("Connections distribution expected to be >= than " + minimumPercentage + + ". Actuall distribution was " + percentage + " for connection " + key, + percentage >= minimumPercentage); + } + } + + protected void assertAllConnectedTo(String url) throws Exception { + for (ActiveMQConnection c : connections) { + assertEquals(url, c.getTransportChannel().getRemoteAddress()); + } + } + + protected void addBroker(String name, BrokerService brokerService) { + brokers.put(name, brokerService); + } + + protected BrokerService getBroker(String name) { + return brokers.get(name); + } + + protected void stopBroker(String name) throws Exception { + BrokerService broker = brokers.remove(name); + broker.stop(); + broker.waitUntilStopped(); + } + + protected BrokerService removeBroker(String name) { + return brokers.remove(name); + } + + protected void destroyBrokerCluster() throws JMSException, Exception { + for (BrokerService b : brokers.values()) { + try { + b.stop(); + b.waitUntilStopped(); + } catch (Exception e) { + // Keep on going, we want to try and stop them all. + logger.info("Error while stopping broker["+ b.getBrokerName() +"] continuing..."); + } + } + brokers.clear(); + } + + protected void shutdownClients() throws JMSException { + for (Connection c : connections) { + c.close(); + } + } + + protected BrokerService createBroker(String brokerName) throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.setUseJmx(false); + answer.setBrokerName(brokerName); + answer.setUseShutdownHook(false); + return answer; + } + + protected void addTransportConnector(BrokerService brokerService, + String connectorName, String uri, boolean clustered) throws Exception { + TransportConnector connector = brokerService.addConnector(uri); + connector.setName(connectorName); + if (clustered) { + connector.setRebalanceClusterClients(true); + connector.setUpdateClusterClients(true); + connector.setUpdateClusterClientsOnRemove(true); + } else { + connector.setRebalanceClusterClients(false); + connector.setUpdateClusterClients(false); + connector.setUpdateClusterClientsOnRemove(false); + } + } + + protected void addNetworkBridge(BrokerService answer, String bridgeName, + String uri, boolean duplex, String destinationFilter) throws Exception { + NetworkConnector network = answer.addNetworkConnector(uri); + network.setName(bridgeName); + network.setDuplex(duplex); + if (destinationFilter != null && !destinationFilter.equals("")) { + network.setDestinationFilter(bridgeName); + } + } + + protected void createClients() throws Exception { + createClients(NUMBER_OF_CLIENTS); + } + + @SuppressWarnings("unused") + protected void createClients(int numOfClients) throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(clientUrl); + for (int i = 0; i < numOfClients; i++) { + ActiveMQConnection c = (ActiveMQConnection) factory.createConnection(); + c.start(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = s.createQueue(getClass().getName()); + MessageConsumer consumer = s.createConsumer(queue); + connections.add(c); + } + } + + public String getClientUrl() { + return clientUrl; + } + + public void setClientUrl(String clientUrl) { + this.clientUrl = clientUrl; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverComplexClusterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverComplexClusterTest.java new file mode 100644 index 0000000000..fab2da50cb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverComplexClusterTest.java @@ -0,0 +1,380 @@ +/** + * 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.transport.failover; + +import org.apache.activemq.broker.TransportConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Complex cluster test that will exercise the dynamic failover capabilities of + * a network of brokers. Using a networking of 3 brokers where the 3rd broker is + * removed and then added back in it is expected in each test that the number of + * connections on the client should start with 3, then have two after the 3rd + * broker is removed and then show 3 after the 3rd broker is reintroduced. + */ +public class FailoverComplexClusterTest 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 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"; + + /** + * Basic dynamic failover 3 broker test + * + * @throws Exception + */ + public void testThreeBrokerClusterSingleConnectorBasic() throws Exception { + + initSingleTcBroker("", null, null); + + Thread.sleep(2000); + + setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + createClients(); + Thread.sleep(2000); + + runTests(false, null, null, null); + } + + /** + * Tests a 3 broker configuration to ensure that the backup is random and + * supported in a cluster. useExponentialBackOff is set to false and + * maxReconnectAttempts is set to 1 to move through the list quickly for + * this test. + * + * @throws Exception + */ + public void testThreeBrokerClusterSingleConnectorBackupFailoverConfig() throws Exception { + + 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"); + createClients(); + Thread.sleep(2000); + + runTests(false, null, null, null); + } + + /** + * Tests a 3 broker cluster that passes in connection params on the + * transport connector. Prior versions of AMQ passed the TC connection + * params to the client and this should not happen. The chosen param is not + * compatible with the client and will throw an error if used. + * + * @throws Exception + */ + 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 + ")"); + createClients(); + Thread.sleep(2000); + + runTests(false, null, null, null); + } + + /** + * Tests a 3 broker cluster using a cluster filter of * + * + * @throws Exception + */ + 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 + ")"); + createClients(); + + runTests(false, null, "*", null); + } + + /** + * Test to verify that a broker with multiple transport connections only the + * one marked to update clients is propagate + * + * @throws Exception + */ + public void testThreeBrokerClusterMultipleConnectorBasic() throws Exception { + + initMultiTcCluster("", null); + + Thread.sleep(2000); + + setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + createClients(); + Thread.sleep(2000); + + runTests(true, null, null, null); + } + + /** + * Test to verify the reintroduction of the A Broker + * + * @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 + ")"); + createClients(); + Thread.sleep(2000); + + assertClientsConnectedToThreeBrokers(); + + getBroker(BROKER_A_NAME).stop(); + getBroker(BROKER_A_NAME).waitUntilStopped(); + removeBroker(BROKER_A_NAME); + + Thread.sleep(5000); + + assertClientsConnectedToTwoBrokers(); + + createBrokerA(false, null, null, null); + getBroker(BROKER_A_NAME).waitUntilStarted(); + Thread.sleep(5000); + + assertClientsConnectedToThreeBrokers(); + } + + /** + * Test to ensure clients are evenly to all available brokers in the + * network. + * + * @throws Exception + */ + 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"); + createClients(100); + Thread.sleep(5000); + + runClientDistributionTests(false, null, null, null); + } + + /** + * Test to verify that clients are distributed with no less than 20% of the + * clients on any one broker. + * + * @throws Exception + */ + public void testThreeBrokerClusterDestinationFilter() throws Exception { + + initSingleTcBroker("", null, null); + + Thread.sleep(2000); + setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + createClients(); + + runTests(false, null, null, "Queue.TEST.FOO.>"); + } + + public void testFailOverWithUpdateClientsOnRemove() throws Exception{ + // Broker A + addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); + TransportConnector connectorA = getBroker(BROKER_A_NAME).addConnector(BROKER_A_CLIENT_TC_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); + getBroker(BROKER_A_NAME).start(); + + // Broker B + addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); + TransportConnector connectorB = getBroker(BROKER_B_NAME).addConnector(BROKER_B_CLIENT_TC_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); + getBroker(BROKER_B_NAME).start(); + + getBroker(BROKER_B_NAME).waitUntilStarted(); + Thread.sleep(1000); + + // 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"); + createClients(1); + Thread.sleep(5000); + + // We stop broker A. + logger.info("Stopping broker A whose address is: {}", BROKER_A_CLIENT_TC_ADDRESS); + getBroker(BROKER_A_NAME).stop(); + getBroker(BROKER_A_NAME).waitUntilStopped(); + Thread.sleep(5000); + + // Client should failover to B. + assertAllConnectedTo(BROKER_B_CLIENT_TC_ADDRESS); + } + + /** + * Runs a 3 Broker dynamic failover test:
+ *
    + *
  • asserts clients are distributed across all 3 brokers
  • + *
  • asserts clients are distributed across 2 brokers after removing the 3rd
  • + *
  • asserts clients are distributed across all 3 brokers after + * reintroducing the 3rd broker
  • + *
+ * + * @param multi + * @param tcParams + * @param clusterFilter + * @param destinationFilter + * @throws Exception + * @throws InterruptedException + */ + private void runTests(boolean multi, String tcParams, String clusterFilter, String destinationFilter) throws Exception, InterruptedException { + assertClientsConnectedToThreeBrokers(); + + getBroker(BROKER_C_NAME).stop(); + getBroker(BROKER_C_NAME).waitUntilStopped(); + removeBroker(BROKER_C_NAME); + + Thread.sleep(5000); + + assertClientsConnectedToTwoBrokers(); + + createBrokerC(multi, tcParams, clusterFilter, destinationFilter); + getBroker(BROKER_C_NAME).waitUntilStarted(); + Thread.sleep(5000); + + assertClientsConnectedToThreeBrokers(); + } + + /** + * @param multi + * @param tcParams + * @param clusterFilter + * @param destinationFilter + * @throws Exception + * @throws InterruptedException + */ + private void runClientDistributionTests(boolean multi, String tcParams, String clusterFilter, String destinationFilter) throws Exception, InterruptedException { + assertClientsConnectedToThreeBrokers(); + assertClientsConnectionsEvenlyDistributed(.25); + + getBroker(BROKER_C_NAME).stop(); + getBroker(BROKER_C_NAME).waitUntilStopped(); + removeBroker(BROKER_C_NAME); + + Thread.sleep(5000); + + assertClientsConnectedToTwoBrokers(); + assertClientsConnectionsEvenlyDistributed(.35); + + createBrokerC(multi, tcParams, clusterFilter, destinationFilter); + getBroker(BROKER_C_NAME).waitUntilStarted(); + Thread.sleep(5000); + + assertClientsConnectedToThreeBrokers(); + assertClientsConnectionsEvenlyDistributed(.20); + } + + @Override + 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); + getBroker(BROKER_C_NAME).waitUntilStarted(); + } + + private void initMultiTcCluster(String params, String clusterFilter) throws Exception { + createBrokerA(true, params, clusterFilter, null); + createBrokerB(true, params, clusterFilter, null); + createBrokerC(true, params, clusterFilter, null); + getBroker(BROKER_C_NAME).waitUntilStarted(); + } + + private void createBrokerA(boolean multi, String params, String clusterFilter, String destinationFilter) throws Exception { + final String tcParams = (params == null)?"":params; + if (getBroker(BROKER_A_NAME) == null) { + 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); + } 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); + } + 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); + 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); + } 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); + } + getBroker(BROKER_B_NAME).start(); + } + } + + private void createBrokerC(boolean multi, String params, String clusterFilter, String destinationFilter) throws Exception { + final String tcParams = (params == null)?"":params; + if (getBroker(BROKER_C_NAME) == null) { + 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); + } 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); + } + getBroker(BROKER_C_NAME).start(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverConsumerOutstandingCommitTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverConsumerOutstandingCommitTest.java new file mode 100644 index 0000000000..9c08c81e63 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverConsumerOutstandingCommitTest.java @@ -0,0 +1,372 @@ +/** + * 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.transport.failover; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.TransactionId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.junit.After; +import org.junit.Test; + +public class FailoverConsumerOutstandingCommitTest { + + private static final Logger LOG = LoggerFactory.getLogger(FailoverConsumerOutstandingCommitTest.class); + private static final String QUEUE_NAME = "FailoverWithOutstandingCommit"; + private static final String MESSAGE_TEXT = "Test message "; + private static final String TRANSPORT_URI = "tcp://localhost:0"; + private String url; + final int prefetch = 10; + BrokerService broker; + + @After + public void stopBroker() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + public void startBroker(boolean deleteAllMessagesOnStartup) throws Exception { + broker = createBroker(deleteAllMessagesOnStartup); + broker.start(); + } + + public BrokerService createBroker(boolean deleteAllMessagesOnStartup) throws Exception { + return createBroker(deleteAllMessagesOnStartup, TRANSPORT_URI); + } + + public BrokerService createBroker(boolean deleteAllMessagesOnStartup, String bindAddress) throws Exception { + broker = new BrokerService(); + broker.addConnector(bindAddress); + broker.setDeleteAllMessagesOnStartup(deleteAllMessagesOnStartup); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + + // optimizedDispatche and sync dispatch ensure that the dispatch happens + // before the commit reply that the consumer.clearDispatchList is waiting for. + defaultEntry.setOptimizedDispatch(true); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + + url = broker.getTransportConnectors().get(0).getConnectUri().toString(); + + return broker; + } + + @Test + public void testFailoverConsumerDups() throws Exception { + doTestFailoverConsumerDups(true); + } + + @SuppressWarnings("unchecked") + public void doTestFailoverConsumerDups(final boolean watchTopicAdvisories) throws Exception { + + broker = createBroker(true); + + broker.setPlugins(new BrokerPlugin[] { + new BrokerPluginSupport() { + @Override + public void commitTransaction(ConnectionContext context, + TransactionId xid, boolean onePhase) throws Exception { + // so commit will hang as if reply is lost + context.setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping broker before commit..."); + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + }); + broker.start(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + cf.setWatchTopicAdvisories(watchTopicAdvisories); + cf.setDispatchAsync(false); + + final ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + + final Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME + "?consumer.prefetchSize=" + prefetch); + + final Session consumerSession = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + final CountDownLatch commitDoneLatch = new CountDownLatch(1); + final CountDownLatch messagesReceived = new CountDownLatch(2); + + final MessageConsumer testConsumer = consumerSession.createConsumer(destination); + testConsumer.setMessageListener(new MessageListener() { + + public void onMessage(Message message) { + LOG.info("consume one and commit"); + + assertNotNull("got message", message); + + try { + consumerSession.commit(); + } catch (JMSException e) { + e.printStackTrace(); + } + commitDoneLatch.countDown(); + messagesReceived.countDown(); + LOG.info("done commit"); + } + }); + + // may block if broker shutodwn happens quickly + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("producer started"); + try { + produceMessage(producerSession, destination, prefetch * 2); + } catch (javax.jms.IllegalStateException SessionClosedExpectedOnShutdown) { + } catch (JMSException e) { + e.printStackTrace(); + fail("unexpceted ex on producer: " + e); + } + LOG.info("producer done"); + } + }); + + // will be stopped by the plugin + broker.waitUntilStopped(); + broker = createBroker(false, url); + broker.start(); + + assertTrue("consumer added through failover", commitDoneLatch.await(20, TimeUnit.SECONDS)); + assertTrue("another message was recieved after failover", messagesReceived.await(20, TimeUnit.SECONDS)); + + connection.close(); + } + + @Test + public void TestFailoverConsumerOutstandingSendTxIncomplete() throws Exception { + doTestFailoverConsumerOutstandingSendTx(false); + } + + @Test + public void TestFailoverConsumerOutstandingSendTxComplete() throws Exception { + doTestFailoverConsumerOutstandingSendTx(true); + } + + @SuppressWarnings("unchecked") + public void doTestFailoverConsumerOutstandingSendTx(final boolean doActualBrokerCommit) throws Exception { + final boolean watchTopicAdvisories = true; + broker = createBroker(true); + + broker.setPlugins(new BrokerPlugin[] { new BrokerPluginSupport() { + @Override + public void commitTransaction(ConnectionContext context, + TransactionId xid, boolean onePhase) throws Exception { + // from the consumer perspective whether the commit completed on the broker or + // not is irrelevant, the transaction is still in doubt in the absence of a reply + if (doActualBrokerCommit) { + LOG.info("doing actual broker commit..."); + super.commitTransaction(context, xid, onePhase); + } + // so commit will hang as if reply is lost + context.setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping broker before commit..."); + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } }); + broker.start(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + cf.setWatchTopicAdvisories(watchTopicAdvisories); + cf.setDispatchAsync(false); + + final ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + + final Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME + + "?consumer.prefetchSize=" + prefetch); + + final Queue signalDestination = producerSession.createQueue(QUEUE_NAME + ".signal" + + "?consumer.prefetchSize=" + prefetch); + + final Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + + final CountDownLatch commitDoneLatch = new CountDownLatch(1); + final CountDownLatch messagesReceived = new CountDownLatch(3); + final AtomicBoolean gotCommitException = new AtomicBoolean(false); + final ArrayList receivedMessages = new ArrayList(); + final MessageConsumer testConsumer = consumerSession.createConsumer(destination); + testConsumer.setMessageListener(new MessageListener() { + + public void onMessage(Message message) { + LOG.info("consume one and commit: " + message); + assertNotNull("got message", message); + receivedMessages.add((TextMessage) message); + try { + produceMessage(consumerSession, signalDestination, 1); + consumerSession.commit(); + } catch (JMSException e) { + LOG.info("commit exception", e); + gotCommitException.set(true); + } + commitDoneLatch.countDown(); + messagesReceived.countDown(); + LOG.info("done commit"); + } + }); + + // may block if broker shutdown happens quickly + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("producer started"); + try { + produceMessage(producerSession, destination, prefetch * 2); + } catch (javax.jms.IllegalStateException SessionClosedExpectedOnShutdown) { + } catch (JMSException e) { + e.printStackTrace(); + fail("unexpceted ex on producer: " + e); + } + LOG.info("producer done"); + } + }); + + // will be stopped by the plugin + broker.waitUntilStopped(); + broker = createBroker(false, url); + broker.start(); + + assertTrue("commit done through failover", commitDoneLatch.await(20, TimeUnit.SECONDS)); + assertTrue("commit failed", gotCommitException.get()); + assertTrue("another message was received after failover", messagesReceived.await(20, TimeUnit.SECONDS)); + int receivedIndex = 0; + assertEquals("get message 0 first", MESSAGE_TEXT + "0", receivedMessages.get(receivedIndex++).getText()); + if (!doActualBrokerCommit) { + // it will be redelivered and not tracked as a duplicate + assertEquals("get message 0 second", MESSAGE_TEXT + "0", receivedMessages.get(receivedIndex++).getText()); + } + assertTrue("another message was received", messagesReceived.await(20, TimeUnit.SECONDS)); + assertEquals("get message 1 eventually", MESSAGE_TEXT + "1", receivedMessages.get(receivedIndex++).getText()); + + connection.close(); + } + + @Test + public void testRollbackFailoverConsumerTx() throws Exception { + broker = createBroker(true); + broker.start(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + cf.setConsumerFailoverRedeliveryWaitPeriod(10000); + final ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + + final Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME); + + final Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + final MessageConsumer testConsumer = consumerSession.createConsumer(destination); + assertNull("no message yet", testConsumer.receiveNoWait()); + + produceMessage(producerSession, destination, 1); + producerSession.close(); + + // consume then rollback after restart + Message msg = testConsumer.receive(5000); + assertNotNull(msg); + + // restart with outstanding delivered message + broker.stop(); + broker.waitUntilStopped(); + broker = createBroker(false, url); + broker.start(); + + consumerSession.rollback(); + + // receive again + msg = testConsumer.receive(10000); + assertNotNull("got message again after rollback", msg); + + consumerSession.commit(); + + // close before sweep + consumerSession.close(); + msg = receiveMessage(cf, destination); + assertNull("should be nothing left after commit", msg); + connection.close(); + } + + private Message receiveMessage(ActiveMQConnectionFactory cf, + Queue destination) throws Exception { + final ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + final Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + final MessageConsumer consumer = consumerSession.createConsumer(destination); + Message msg = consumer.receive(5000); + consumerSession.commit(); + connection.close(); + return msg; + } + + private void produceMessage(final Session producerSession, Queue destination, long count) + throws JMSException { + MessageProducer producer = producerSession.createProducer(destination); + for (int i=0; i urls = new HashMap(); + + @Override + public void setUp() throws Exception { + super.setUp(); + urls.put(BROKER_A_NAME, BROKER_A_CLIENT_TC_ADDRESS); + 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); + + assertAllConnectedTo(urls.get(BROKER_A_NAME)); + + + restart(false, BROKER_A_NAME, BROKER_B_NAME); + + for (int i = 0; i < 3; i++) { + 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); + + for (int i = 0; i < 3; i++) { + restart(true, BROKER_B_NAME, BROKER_A_NAME); + } + + restart(false, BROKER_B_NAME, BROKER_A_NAME); + + } + + public void testThreeBrokers() throws Exception { + // Broker A + addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); + addTransportConnector(getBroker(BROKER_A_NAME), "openwire", BROKER_A_CLIENT_TC_ADDRESS, false); + addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_C_Bridge", "static://(" + BROKER_C_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + getBroker(BROKER_A_NAME).start(); + + // Broker B + addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); + addTransportConnector(getBroker(BROKER_B_NAME), "openwire", BROKER_B_CLIENT_TC_ADDRESS, false); + addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_C_Bridge", "static://(" + BROKER_C_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + getBroker(BROKER_B_NAME).start(); + + // Broker C + addBroker(BROKER_C_NAME, createBroker(BROKER_C_NAME)); + addTransportConnector(getBroker(BROKER_C_NAME), "openwire", BROKER_C_CLIENT_TC_ADDRESS, false); + addNetworkBridge(getBroker(BROKER_C_NAME), "C_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + 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"); + + createClients(5); + + assertAllConnectedTo(urls.get(BROKER_A_NAME)); + + restart(true, BROKER_A_NAME, BROKER_B_NAME); + + } + + public void testPriorityBackupAndUpdateClients() throws Exception { + // Broker A + addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); + addTransportConnector(getBroker(BROKER_A_NAME), "openwire", BROKER_A_CLIENT_TC_ADDRESS, true); + addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + getBroker(BROKER_A_NAME).start(); + + // Broker B + addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); + addTransportConnector(getBroker(BROKER_B_NAME), "openwire", BROKER_B_CLIENT_TC_ADDRESS, true); + addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + 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"); + + LOG.info("Client URI will be: " + getClientUrl()); + + 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); + + if (primary) { + assertAllConnectedTo(urls.get(secondaryName)); + } else { + assertAllConnectedTo(urls.get(primaryName)); + } + + if (primary) { + LOG.info("Starting " + primaryName); + createBrokerByName(primaryName); + getBroker(primaryName).waitUntilStarted(); + } else { + LOG.info("Starting " + secondaryName); + createBrokerByName(secondaryName); + getBroker(secondaryName).waitUntilStarted(); + } + + Thread.sleep(5000); + + assertAllConnectedTo(urls.get(primaryName)); + + } + + private void createBrokerByName(String name) throws Exception { + if (name.equals(BROKER_A_NAME)) { + createBrokerA(); + } else if (name.equals(BROKER_B_NAME)) { + createBrokerB(); + } else { + throw new Exception("Unknown broker " + name); + } + } + + private void createBrokerA() throws Exception { + if (getBroker(BROKER_A_NAME) == null) { + addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); + addTransportConnector(getBroker(BROKER_A_NAME), "openwire", BROKER_A_CLIENT_TC_ADDRESS, false); + addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + getBroker(BROKER_A_NAME).start(); + } + } + + private void createBrokerB() throws Exception { + 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, false); + addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + getBroker(BROKER_B_NAME).start(); + } + } + + @Override + protected void tearDown() throws Exception { + shutdownClients(); + destroyBrokerCluster(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverRandomTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverRandomTest.java new file mode 100644 index 0000000000..8998fe78d4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverRandomTest.java @@ -0,0 +1,77 @@ +/** + * 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.transport.failover; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; + +public class FailoverRandomTest extends TestCase { + + BrokerService brokerA, brokerB; + + public void setUp() throws Exception { + brokerA = createBroker("A"); + brokerB = createBroker("B"); + } + + public void tearDown() throws Exception { + brokerA.stop(); + brokerB.stop(); + } + + private BrokerService createBroker(String name) throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("Broker"+ name); + broker.addConnector("tcp://localhost:0"); + broker.getManagementContext().setCreateConnector(false); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.start(); + return broker; + } + + public void testRandomConnections() throws Exception { + String failoverUrl = "failover:(" + + brokerA.getTransportConnectors().get(0).getConnectUri() + + "," + + brokerB.getTransportConnectors().get(0).getConnectUri() + + ")"; + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(failoverUrl); + + + ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + String brokerName1 = connection.getBrokerName(); + assertNotNull(brokerName1); + connection.close(); + + String brokerName2 = brokerName1; + int attempts = 40; + while (brokerName1.equals(brokerName2) && attempts-- > 0) { + connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + brokerName2 = connection.getBrokerName(); + assertNotNull(brokerName2); + connection.close(); + } + assertTrue(brokerName1 + "!=" + brokerName2, !brokerName1.equals(brokerName2)); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverRedeliveryTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverRedeliveryTransactionTest.java new file mode 100644 index 0000000000..c8d4c511a6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverRedeliveryTransactionTest.java @@ -0,0 +1,88 @@ +/** + * 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.transport.failover; + +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; + +public class FailoverRedeliveryTransactionTest extends FailoverTransactionTest { + + public static Test suite() { + return suite(FailoverRedeliveryTransactionTest.class); + } + + @Override + public void configureConnectionFactory(ActiveMQConnectionFactory factory) { + super.configureConnectionFactory(factory); + factory.setTransactedIndividualAck(true); + } + + @Override + public BrokerService createBroker(boolean deleteAllMessagesOnStartup, String bindAddress) throws Exception { + BrokerService brokerService = super.createBroker(deleteAllMessagesOnStartup, bindAddress); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setPersistJMSRedelivered(true); + policyMap.setDefaultEntry(defaultEntry); + brokerService.setDestinationPolicy(policyMap); + return brokerService; + } + + // no point rerunning these + @Override + public void testFailoverProducerCloseBeforeTransaction() throws Exception { + } + + @Override + public void initCombosForTestFailoverCommitReplyLost() { + } + + @Override + public void testFailoverCommitReplyLost() throws Exception { + } + + @Override + public void testFailoverCommitReplyLostWithDestinationPathSeparator() throws Exception { + } + + @Override + public void initCombosForTestFailoverSendReplyLost() { + } + + @Override + public void testFailoverSendReplyLost() throws Exception { + } + + @Override + public void initCombosForTestFailoverConnectionSendReplyLost() { + } + + @Override + public void testFailoverConnectionSendReplyLost() throws Exception { + } + + @Override + public void testFailoverProducerCloseBeforeTransactionFailWhenDisabled() throws Exception { + } + + @Override + public void testFailoverMultipleProducerCloseBeforeTransaction() throws Exception { + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTimeoutTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTimeoutTest.java new file mode 100644 index 0000000000..9ef6e28bfa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTimeoutTest.java @@ -0,0 +1,136 @@ +/** + * 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.transport.failover; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FailoverTimeoutTest { + + private static final Logger LOG = LoggerFactory.getLogger(FailoverTimeoutTest.class); + + private static final String QUEUE_NAME = "test.failovertimeout"; + BrokerService bs; + URI tcpUri; + + @Before + public void setUp() throws Exception { + bs = new BrokerService(); + bs.setUseJmx(false); + bs.addConnector("tcp://localhost:0"); + bs.start(); + tcpUri = bs.getTransportConnectors().get(0).getConnectUri(); + } + + @After + public void tearDown() throws Exception { + if (bs != null) { + bs.stop(); + } + } + + @Test + public void testTimoutDoesNotFailConnectionAttempts() throws Exception { + bs.stop(); + long timeout = 1000; + + long startTime = System.currentTimeMillis(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory( + "failover:(" + tcpUri + ")" + + "?timeout=" + timeout + "&useExponentialBackOff=false" + + "&maxReconnectAttempts=5" + "&initialReconnectDelay=1000"); + Connection connection = cf.createConnection(); + try { + connection.start(); + fail("Should have failed to connect"); + } catch (JMSException ex) { + LOG.info("Caught exception on call to start: {}", ex.getMessage()); + } + + long endTime = System.currentTimeMillis(); + long duration = endTime - startTime; + + LOG.info("Time spent waiting to connect: {} ms", duration); + + assertTrue(duration > 3000); + } + + @Test + public void testTimeout() throws Exception { + + long timeout = 1000; + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + tcpUri + ")?timeout=" + timeout + "&useExponentialBackOff=false"); + Connection connection = cf.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session + .createQueue(QUEUE_NAME)); + TextMessage message = session.createTextMessage("Test message"); + producer.send(message); + + bs.stop(); + + try { + producer.send(message); + } catch (JMSException jmse) { + assertEquals("Failover timeout of " + timeout + " ms reached.", jmse.getMessage()); + } + + bs = new BrokerService(); + bs.setUseJmx(false); + bs.addConnector(tcpUri); + bs.start(); + bs.waitUntilStarted(); + + producer.send(message); + + bs.stop(); + } + + @Test + public void testUpdateUris() throws Exception { + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + tcpUri + ")?useExponentialBackOff=false"); + ActiveMQConnection connection = (ActiveMQConnection) cf.createConnection(); + connection.start(); + FailoverTransport failoverTransport = connection.getTransport().narrow(FailoverTransport.class); + + URI[] bunchOfUnknownAndOneKnown = new URI[]{ + new URI("tcp://unknownHost:" + tcpUri.getPort()), + new URI("tcp://unknownHost2:" + tcpUri.getPort()), + new URI("tcp://localhost:2222")}; + failoverTransport.add(false, bunchOfUnknownAndOneKnown); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransactionTest.java new file mode 100644 index 0000000000..9b41713d9c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransactionTest.java @@ -0,0 +1,1181 @@ +/** + * 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.transport.failover; + +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQMessageConsumer; +import org.apache.activemq.AutoFailTestSupport; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.ConsumerBrokerExchange; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.util.DestinationPathSeparatorBroker; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.TransactionId; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.util.SocketProxy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.ServerSession; +import javax.jms.ServerSessionPool; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TransactionRolledBackException; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.NoSuchElementException; +import java.util.Stack; +import java.util.Vector; +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.AtomicBoolean; + +// see https://issues.apache.org/activemq/browse/AMQ-2473 + +// https://issues.apache.org/activemq/browse/AMQ-2590 +public class FailoverTransactionTest extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(FailoverTransactionTest.class); + private static final String QUEUE_NAME = "Failover.WithTx"; + private static final String TRANSPORT_URI = "tcp://localhost:0"; + private String url; + BrokerService broker; + + public static Test suite() { + return suite(FailoverTransactionTest.class); + } + + public void setUp() throws Exception { + super.setMaxTestTime(2 * 60 * 1000); // some boxes can be real slow + super.setAutoFail(true); + super.setUp(); + } + + public void tearDown() throws Exception { + super.tearDown(); + stopBroker(); + } + + public void stopBroker() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + private void startCleanBroker() throws Exception { + startBroker(true); + } + + public void startBroker(boolean deleteAllMessagesOnStartup) throws Exception { + broker = createBroker(deleteAllMessagesOnStartup); + broker.start(); + } + + public void startBroker(boolean deleteAllMessagesOnStartup, String bindAddress) throws Exception { + broker = createBroker(deleteAllMessagesOnStartup, bindAddress); + broker.start(); + } + + public BrokerService createBroker(boolean deleteAllMessagesOnStartup) throws Exception { + return createBroker(deleteAllMessagesOnStartup, TRANSPORT_URI); + } + + public BrokerService createBroker(boolean deleteAllMessagesOnStartup, String bindAddress) throws Exception { + broker = new BrokerService(); + broker.setUseJmx(false); + broker.setAdvisorySupport(false); + broker.addConnector(bindAddress); + broker.setDeleteAllMessagesOnStartup(deleteAllMessagesOnStartup); + + url = broker.getTransportConnectors().get(0).getConnectUri().toString(); + + return broker; + } + + public void configureConnectionFactory(ActiveMQConnectionFactory factory) { + // nothing to do + } + + public void testFailoverProducerCloseBeforeTransaction() throws Exception { + startCleanBroker(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(QUEUE_NAME); + + MessageConsumer consumer = session.createConsumer(destination); + produceMessage(session, destination); + + // restart to force failover and connection state recovery before the commit + broker.stop(); + startBroker(false, url); + + session.commit(); + assertNotNull("we got the message", consumer.receive(20000)); + session.commit(); + connection.close(); + } + + public void initCombosForTestFailoverCommitReplyLost() { + String osName = System.getProperty("os.name"); + Object[] persistenceAdapters; + if (!osName.equalsIgnoreCase("AIX") && !osName.equalsIgnoreCase("SunOS")) { + persistenceAdapters = new Object[]{PersistenceAdapterChoice.KahaDB, PersistenceAdapterChoice.LevelDB, PersistenceAdapterChoice.JDBC}; + } else { + persistenceAdapters = new Object[]{PersistenceAdapterChoice.KahaDB, PersistenceAdapterChoice.JDBC}; + } + addCombinationValues("defaultPersistenceAdapter",persistenceAdapters); + } + + @SuppressWarnings("unchecked") + public void testFailoverCommitReplyLost() throws Exception { + + broker = createBroker(true); + setDefaultPersistenceAdapter(broker); + + broker.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + @Override + public void commitTransaction(ConnectionContext context, + TransactionId xid, boolean onePhase) throws Exception { + super.commitTransaction(context, xid, onePhase); + // so commit will hang as if reply is lost + context.setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping broker post commit..."); + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + }); + broker.start(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(QUEUE_NAME); + + MessageConsumer consumer = session.createConsumer(destination); + produceMessage(session, destination); + + final CountDownLatch commitDoneLatch = new CountDownLatch(1); + // broker will die on commit reply so this will hang till restart + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("doing async commit..."); + try { + session.commit(); + } catch (JMSException e) { + assertTrue(e instanceof TransactionRolledBackException); + LOG.info("got commit exception: ", e); + } + commitDoneLatch.countDown(); + LOG.info("done async commit"); + } + }); + + // will be stopped by the plugin + broker.waitUntilStopped(); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.start(); + + assertTrue("tx committed through failover", commitDoneLatch.await(30, TimeUnit.SECONDS)); + + // new transaction + Message msg = consumer.receive(20000); + LOG.info("Received: " + msg); + assertNotNull("we got the message", msg); + assertNull("we got just one message", consumer.receive(2000)); + session.commit(); + consumer.close(); + connection.close(); + + // ensure no dangling messages with fresh broker etc + broker.stop(); + broker.waitUntilStopped(); + + LOG.info("Checking for remaining/hung messages.."); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.start(); + + // after restart, ensure no dangling messages + cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + connection = cf.createConnection(); + connection.start(); + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session2.createConsumer(destination); + msg = consumer.receive(1000); + if (msg == null) { + msg = consumer.receive(5000); + } + LOG.info("Received: " + msg); + assertNull("no messges left dangling but got: " + msg, msg); + connection.close(); + } + + @SuppressWarnings("unchecked") + public void testFailoverCommitReplyLostWithDestinationPathSeparator() throws Exception { + + broker = createBroker(true); + setDefaultPersistenceAdapter(broker); + + broker.setPlugins(new BrokerPlugin[]{ + new DestinationPathSeparatorBroker(), + new BrokerPluginSupport() { + @Override + public void commitTransaction(ConnectionContext context, + TransactionId xid, boolean onePhase) throws Exception { + super.commitTransaction(context, xid, onePhase); + // so commit will hang as if reply is lost + context.setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping broker post commit..."); + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + }); + broker.start(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(QUEUE_NAME.replace('.','/') + "?consumer.prefetchSize=0"); + + MessageConsumer consumer = session.createConsumer(destination); + produceMessage(session, destination); + + final CountDownLatch commitDoneLatch = new CountDownLatch(1); + // broker will die on commit reply so this will hang till restart + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("doing async commit..."); + try { + session.commit(); + } catch (JMSException e) { + assertTrue(e instanceof TransactionRolledBackException); + LOG.info("got commit exception: ", e); + } + commitDoneLatch.countDown(); + LOG.info("done async commit"); + } + }); + + // will be stopped by the plugin + broker.waitUntilStopped(); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.setPlugins(new BrokerPlugin[]{new DestinationPathSeparatorBroker()}); + broker.start(); + + assertTrue("tx committed trough failover", commitDoneLatch.await(30, TimeUnit.SECONDS)); + + // new transaction + Message msg = consumer.receive(20000); + LOG.info("Received: " + msg); + assertNotNull("we got the message", msg); + assertNull("we got just one message", consumer.receive(2000)); + session.commit(); + consumer.close(); + connection.close(); + + // ensure no dangling messages with fresh broker etc + broker.stop(); + broker.waitUntilStopped(); + + LOG.info("Checking for remaining/hung messages.."); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.setPlugins(new BrokerPlugin[]{new DestinationPathSeparatorBroker()}); + broker.start(); + + // after restart, ensure no dangling messages + cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + connection = cf.createConnection(); + connection.start(); + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session2.createConsumer(destination); + msg = consumer.receive(1000); + if (msg == null) { + msg = consumer.receive(5000); + } + LOG.info("Received: " + msg); + assertNull("no messges left dangling but got: " + msg, msg); + connection.close(); + + ActiveMQDestination[] destinations = broker.getRegionBroker().getDestinations(); + for (ActiveMQDestination dest : destinations) { + LOG.info("Destinations list: " + dest); + } + assertEquals("Only one destination", 1, broker.getRegionBroker().getDestinations().length); + } + + public void initCombosForTestFailoverSendReplyLost() { + addCombinationValues("defaultPersistenceAdapter", + new Object[]{PersistenceAdapterChoice.KahaDB, + PersistenceAdapterChoice.JDBC + // not implemented for AMQ store or PersistenceAdapterChoice.LevelDB + }); + } + + @SuppressWarnings("unchecked") + public void testFailoverSendReplyLost() throws Exception { + + broker = createBroker(true); + setDefaultPersistenceAdapter(broker); + + broker.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + @Override + public void send(ProducerBrokerExchange producerExchange, + org.apache.activemq.command.Message messageSend) + throws Exception { + // so send will hang as if reply is lost + super.send(producerExchange, messageSend); + producerExchange.getConnectionContext().setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping broker post send..."); + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + }); + broker.start(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")?jms.watchTopicAdvisories=false"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = session.createQueue(QUEUE_NAME); + + MessageConsumer consumer = session.createConsumer(destination); + final CountDownLatch sendDoneLatch = new CountDownLatch(1); + // broker will die on send reply so this will hang till restart + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("doing async send..."); + try { + produceMessage(session, destination); + } catch (JMSException e) { + //assertTrue(e instanceof TransactionRolledBackException); + LOG.error("got send exception: ", e); + fail("got unexpected send exception" + e); + } + sendDoneLatch.countDown(); + LOG.info("done async send"); + } + }); + + // will be stopped by the plugin + broker.waitUntilStopped(); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + LOG.info("restarting...."); + broker.start(); + + assertTrue("message sent through failover", sendDoneLatch.await(30, TimeUnit.SECONDS)); + + // new transaction + Message msg = consumer.receive(20000); + LOG.info("Received: " + msg); + assertNotNull("we got the message", msg); + assertNull("we got just one message", consumer.receive(2000)); + consumer.close(); + connection.close(); + + // verify stats + assertEquals("no newly queued messages", 0, ((RegionBroker) broker.getRegionBroker()).getDestinationStatistics().getEnqueues().getCount()); + assertEquals("1 dequeue", 1, ((RegionBroker) broker.getRegionBroker()).getDestinationStatistics().getDequeues().getCount()); + + // ensure no dangling messages with fresh broker etc + broker.stop(); + broker.waitUntilStopped(); + + LOG.info("Checking for remaining/hung messages with second restart.."); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.start(); + + // after restart, ensure no dangling messages + cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + connection = cf.createConnection(); + connection.start(); + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session2.createConsumer(destination); + msg = consumer.receive(1000); + if (msg == null) { + msg = consumer.receive(5000); + } + LOG.info("Received: " + msg); + assertNull("no messges left dangling but got: " + msg, msg); + connection.close(); + } + + public void initCombosForTestFailoverConnectionSendReplyLost() { + addCombinationValues("defaultPersistenceAdapter", + new Object[]{PersistenceAdapterChoice.KahaDB, + PersistenceAdapterChoice.JDBC + // last producer message id store feature not implemented for AMQ store + // or PersistenceAdapterChoice.LevelDB + }); + } + + @SuppressWarnings("unchecked") + public void testFailoverConnectionSendReplyLost() throws Exception { + + broker = createBroker(true); + PersistenceAdapter store = setDefaultPersistenceAdapter(broker); + if (store instanceof KahaDBPersistenceAdapter) { + // duplicate checker not updated on canceled tasks, even it + // it was, recovery of the audit would fail as the message is + // not recorded in the store and the audit may not be up to date. + // So if duplicate messages are a absolute no no after restarts, + // ConcurrentStoreAndDispatchQueues must be disabled + ((KahaDBPersistenceAdapter) store).setConcurrentStoreAndDispatchQueues(false); + } + + final SocketProxy proxy = new SocketProxy(); + + broker.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + private boolean firstSend = true; + + @Override + public void send(ProducerBrokerExchange producerExchange, + org.apache.activemq.command.Message messageSend) + throws Exception { + // so send will hang as if reply is lost + super.send(producerExchange, messageSend); + if (firstSend) { + firstSend = false; + + producerExchange.getConnectionContext().setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping connection post send..."); + try { + proxy.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + } + }); + broker.start(); + + proxy.setTarget(new URI(url)); + proxy.open(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + proxy.getUrl().toASCIIString() + ")?jms.watchTopicAdvisories=false"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = session.createQueue(QUEUE_NAME); + + MessageConsumer consumer = session.createConsumer(destination); + final CountDownLatch sendDoneLatch = new CountDownLatch(1); + // proxy connection will die on send reply so this will hang on failover reconnect till open + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("doing async send..."); + try { + produceMessage(session, destination); + } catch (JMSException e) { + //assertTrue(e instanceof TransactionRolledBackException); + LOG.info("got send exception: ", e); + } + sendDoneLatch.countDown(); + LOG.info("done async send"); + } + }); + + // will be closed by the plugin + assertTrue("proxy was closed", proxy.waitUntilClosed(30)); + LOG.info("restarting proxy"); + proxy.open(); + + assertTrue("message sent through failover", sendDoneLatch.await(30, TimeUnit.SECONDS)); + + Message msg = consumer.receive(20000); + LOG.info("Received: " + msg); + assertNotNull("we got the message", msg); + assertNull("we got just one message", consumer.receive(2000)); + consumer.close(); + connection.close(); + + // verify stats, connection dup suppression means dups don't get to broker + assertEquals("one queued message", 1, ((RegionBroker) broker.getRegionBroker()).getDestinationStatistics().getEnqueues().getCount()); + + // ensure no dangling messages with fresh broker etc + broker.stop(); + broker.waitUntilStopped(); + + LOG.info("Checking for remaining/hung messages with restart.."); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.start(); + + // after restart, ensure no dangling messages + cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + connection = cf.createConnection(); + connection.start(); + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session2.createConsumer(destination); + msg = consumer.receive(1000); + if (msg == null) { + msg = consumer.receive(5000); + } + LOG.info("Received: " + msg); + assertNull("no messges left dangling but got: " + msg, msg); + connection.close(); + } + + public void testFailoverProducerCloseBeforeTransactionFailWhenDisabled() throws Exception { + startCleanBroker(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")?trackTransactionProducers=false"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(QUEUE_NAME); + + MessageConsumer consumer = session.createConsumer(destination); + produceMessage(session, destination); + + // restart to force failover and connection state recovery before the commit + broker.stop(); + startBroker(false, url); + + session.commit(); + + // without tracking producers, message will not be replayed on recovery + assertNull("we got the message", consumer.receive(5000)); + session.commit(); + connection.close(); + } + + public void testFailoverMultipleProducerCloseBeforeTransaction() throws Exception { + startCleanBroker(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(QUEUE_NAME); + + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer; + TextMessage message; + final int count = 10; + for (int i = 0; i < count; i++) { + producer = session.createProducer(destination); + message = session.createTextMessage("Test message: " + count); + producer.send(message); + producer.close(); + } + + // restart to force failover and connection state recovery before the commit + broker.stop(); + startBroker(false, url); + + session.commit(); + for (int i = 0; i < count; i++) { + assertNotNull("we got all the message: " + count, consumer.receive(20000)); + } + session.commit(); + connection.close(); + } + + // https://issues.apache.org/activemq/browse/AMQ-2772 + public void testFailoverWithConnectionConsumer() throws Exception { + startCleanBroker(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(QUEUE_NAME); + + final CountDownLatch connectionConsumerGotOne = new CountDownLatch(1); + final Session poolSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.createConnectionConsumer(destination, null, new ServerSessionPool() { + public ServerSession getServerSession() throws JMSException { + return new ServerSession() { + public Session getSession() throws JMSException { + return poolSession; + } + + public void start() throws JMSException { + connectionConsumerGotOne.countDown(); + poolSession.run(); + } + }; + } + }, 1); + + MessageConsumer consumer = session.createConsumer(destination); + MessageProducer producer; + TextMessage message; + final int count = 10; + for (int i = 0; i < count; i++) { + producer = session.createProducer(destination); + message = session.createTextMessage("Test message: " + count); + producer.send(message); + producer.close(); + } + + // restart to force failover and connection state recovery before the commit + broker.stop(); + startBroker(false, url); + + session.commit(); + for (int i = 0; i < count - 1; i++) { + assertNotNull("Failed to get message: " + count, consumer.receive(20000)); + } + session.commit(); + connection.close(); + + assertTrue("connectionconsumer did not get a message", connectionConsumerGotOne.await(10, TimeUnit.SECONDS)); + } + + public void testFailoverConsumerAckLost() throws Exception { + // as failure depends on hash order of state tracker recovery, do a few times + for (int i = 0; i < 3; i++) { + try { + LOG.info("Iteration: " + i); + doTestFailoverConsumerAckLost(i); + } finally { + stopBroker(); + } + } + } + + @SuppressWarnings("unchecked") + public void doTestFailoverConsumerAckLost(final int pauseSeconds) throws Exception { + broker = createBroker(true); + setDefaultPersistenceAdapter(broker); + + broker.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + + // broker is killed on delivered ack as prefetch is 1 + @Override + public void acknowledge( + ConsumerBrokerExchange consumerExchange, + final MessageAck ack) throws Exception { + + consumerExchange.getConnectionContext().setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping broker on ack: " + ack); + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + }); + broker.start(); + + Vector connections = new Vector(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + connections.add(connection); + final Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME + "?consumer.prefetchSize=1"); + + connection = cf.createConnection(); + connection.start(); + connections.add(connection); + final Session consumerSession1 = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + connection = cf.createConnection(); + connection.start(); + connections.add(connection); + final Session consumerSession2 = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + final MessageConsumer consumer1 = consumerSession1.createConsumer(destination); + final MessageConsumer consumer2 = consumerSession2.createConsumer(destination); + + produceMessage(producerSession, destination); + produceMessage(producerSession, destination); + + final Vector receivedMessages = new Vector(); + final CountDownLatch commitDoneLatch = new CountDownLatch(1); + final AtomicBoolean gotTransactionRolledBackException = new AtomicBoolean(false); + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("doing async commit after consume..."); + try { + Message msg = consumer1.receive(20000); + LOG.info("consumer1 first attempt got message: " + msg); + receivedMessages.add(msg); + + // give some variance to the runs + TimeUnit.SECONDS.sleep(pauseSeconds * 2); + + // should not get a second message as there are two messages and two consumers + // and prefetch=1, but with failover and unordered connection restore it can get the second + // message. + + // For the transaction to complete it needs to get the same one or two messages + // again so that the acks line up. + // If redelivery order is different, the commit should fail with an ex + // + msg = consumer1.receive(5000); + LOG.info("consumer1 second attempt got message: " + msg); + if (msg != null) { + receivedMessages.add(msg); + } + + LOG.info("committing consumer1 session: " + receivedMessages.size() + " messsage(s)"); + try { + consumerSession1.commit(); + } catch (JMSException expectedSometimes) { + LOG.info("got exception ex on commit", expectedSometimes); + if (expectedSometimes instanceof TransactionRolledBackException) { + gotTransactionRolledBackException.set(true); + // ok, message one was not replayed so we expect the rollback + } else { + throw expectedSometimes; + } + + } + commitDoneLatch.countDown(); + LOG.info("done async commit"); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + // will be stopped by the plugin + broker.waitUntilStopped(); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.start(); + + assertTrue("tx committed through failover", commitDoneLatch.await(30, TimeUnit.SECONDS)); + + LOG.info("received message count: " + receivedMessages.size()); + + // new transaction + Message msg = consumer1.receive(gotTransactionRolledBackException.get() ? 5000 : 20000); + LOG.info("post: from consumer1 received: " + msg); + if (gotTransactionRolledBackException.get()) { + assertNotNull("should be available again after commit rollback ex", msg); + } else { + assertNull("should be nothing left for consumer as receive should have committed", msg); + } + consumerSession1.commit(); + + if (gotTransactionRolledBackException.get() || + !gotTransactionRolledBackException.get() && receivedMessages.size() == 1) { + // just one message successfully consumed or none consumed + // consumer2 should get other message + msg = consumer2.receive(10000); + LOG.info("post: from consumer2 received: " + msg); + assertNotNull("got second message on consumer2", msg); + consumerSession2.commit(); + } + + for (Connection c : connections) { + c.close(); + } + + // ensure no dangling messages with fresh broker etc + broker.stop(); + broker.waitUntilStopped(); + + LOG.info("Checking for remaining/hung messages.."); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.start(); + + // after restart, ensure no dangling messages + cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + connection = cf.createConnection(); + connection.start(); + Session sweeperSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer sweeper = sweeperSession.createConsumer(destination); + msg = sweeper.receive(1000); + if (msg == null) { + msg = sweeper.receive(5000); + } + LOG.info("Sweep received: " + msg); + assertNull("no messges left dangling but got: " + msg, msg); + connection.close(); + } + + public void testPoolingNConsumesAfterReconnect() throws Exception { + broker = createBroker(true); + setDefaultPersistenceAdapter(broker); + + broker.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + int count = 0; + + @Override + public void removeConsumer(ConnectionContext context, final ConsumerInfo info) throws Exception { + if (count++ == 1) { + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("Stopping broker on removeConsumer: " + info); + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + } + }); + broker.start(); + + Vector connections = new Vector(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME + "?consumer.prefetchSize=1"); + + produceMessage(producerSession, destination); + connection.close(); + + connection = cf.createConnection(); + connection.start(); + connections.add(connection); + final Session consumerSession = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + final int sessionCount = 10; + final Stack sessions = new Stack(); + for (int i = 0; i < sessionCount; i++) { + sessions.push(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); + } + + final int consumerCount = 1000; + final Deque consumers = new ArrayDeque(); + for (int i = 0; i < consumerCount; i++) { + consumers.push(consumerSession.createConsumer(destination)); + } + final ExecutorService executorService = Executors.newCachedThreadPool(); + + final FailoverTransport failoverTransport = ((ActiveMQConnection) connection).getTransport().narrow(FailoverTransport.class); + final TransportListener delegate = failoverTransport.getTransportListener(); + failoverTransport.setTransportListener(new TransportListener() { + @Override + public void onCommand(Object command) { + delegate.onCommand(command); + } + + @Override + public void onException(IOException error) { + delegate.onException(error); + } + + @Override + public void transportInterupted() { + + LOG.error("Transport interrupted: " + failoverTransport, new RuntimeException("HERE")); + for (int i = 0; i < consumerCount && !consumers.isEmpty(); i++) { + + executorService.execute(new Runnable() { + public void run() { + MessageConsumer localConsumer = null; + try { + synchronized (delegate) { + localConsumer = consumers.pop(); + } + localConsumer.receive(1); + + LOG.info("calling close() " + ((ActiveMQMessageConsumer) localConsumer).getConsumerId()); + localConsumer.close(); + } catch (NoSuchElementException nse) { + } catch (Exception ignored) { + LOG.error("Ex on: " + ((ActiveMQMessageConsumer) localConsumer).getConsumerId(), ignored); + } + } + }); + } + + delegate.transportInterupted(); + } + + @Override + public void transportResumed() { + delegate.transportResumed(); + } + }); + + + MessageConsumer consumer = null; + synchronized (delegate) { + consumer = consumers.pop(); + } + LOG.info("calling close to trigger broker stop " + ((ActiveMQMessageConsumer) consumer).getConsumerId()); + consumer.close(); + + // will be stopped by the plugin + broker.waitUntilStopped(); + broker = createBroker(false, url); + setDefaultPersistenceAdapter(broker); + broker.start(); + + consumer = consumerSession.createConsumer(destination); + LOG.info("finally consuming message: " + ((ActiveMQMessageConsumer) consumer).getConsumerId()); + + Message msg = null; + for (int i = 0; i < 4 && msg == null; i++) { + msg = consumer.receive(1000); + } + LOG.info("post: from consumer1 received: " + msg); + assertNotNull("got message after failover", msg); + msg.acknowledge(); + + for (Connection c : connections) { + c.close(); + } + } + + public void testAutoRollbackWithMissingRedeliveries() throws Exception { + broker = createBroker(true); + broker.start(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + final Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME + "?consumer.prefetchSize=1"); + final Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = consumerSession.createConsumer(destination); + + produceMessage(producerSession, destination); + + Message msg = consumer.receive(20000); + assertNotNull(msg); + + broker.stop(); + broker = createBroker(false, url); + // use empty jdbc store so that default wait(0) for redeliveries will timeout after failover + setPersistenceAdapter(broker, PersistenceAdapterChoice.JDBC); + broker.start(); + + try { + consumerSession.commit(); + fail("expected transaciton rolledback ex"); + } catch (TransactionRolledBackException expected) { + } + + broker.stop(); + broker = createBroker(false, url); + broker.start(); + + assertNotNull("should get rolledback message from original restarted broker", consumer.receive(20000)); + connection.close(); + } + + public void testWaitForMissingRedeliveries() throws Exception { + LOG.info("testWaitForMissingRedeliveries()"); + broker = createBroker(true); + broker.start(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")?jms.consumerFailoverRedeliveryWaitPeriod=30000"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + final Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME); + final Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = consumerSession.createConsumer(destination); + + produceMessage(producerSession, destination); + Message msg = consumer.receive(20000); + if (msg == null) { + AutoFailTestSupport.dumpAllThreads("missing-"); + } + assertNotNull("got message just produced", msg); + + broker.stop(); + broker = createBroker(false, url); + // use empty jdbc store so that wait for re-deliveries occur when failover resumes + setPersistenceAdapter(broker, PersistenceAdapterChoice.JDBC); + broker.start(); + + final CountDownLatch commitDone = new CountDownLatch(1); + // will block pending re-deliveries + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("doing async commit..."); + try { + consumerSession.commit(); + commitDone.countDown(); + } catch (JMSException ignored) { + } + } + }); + + broker.stop(); + broker = createBroker(false, url); + broker.start(); + + assertTrue("commit was successful", commitDone.await(30, TimeUnit.SECONDS)); + + assertNull("should not get committed message", consumer.receive(5000)); + connection.close(); + } + + public void testReDeliveryWhilePending() throws Exception { + LOG.info("testReDeliveryWhilePending()"); + broker = createBroker(true); + broker.start(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + url + ")?jms.consumerFailoverRedeliveryWaitPeriod=10000"); + configureConnectionFactory(cf); + Connection connection = cf.createConnection(); + connection.start(); + final Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue destination = producerSession.createQueue(QUEUE_NAME + "?consumer.prefetchSize=0"); + final Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = consumerSession.createConsumer(destination); + + produceMessage(producerSession, destination); + Message msg = consumer.receive(20000); + if (msg == null) { + AutoFailTestSupport.dumpAllThreads("missing-"); + } + assertNotNull("got message just produced", msg); + + // add another consumer into the mix that may get the message after restart + MessageConsumer consumer2 = consumerSession.createConsumer(consumerSession.createQueue(QUEUE_NAME + "?consumer.prefetchSize=1")); + + broker.stop(); + broker = createBroker(false, url); + broker.start(); + + final CountDownLatch commitDone = new CountDownLatch(1); + + final Vector exceptions = new Vector(); + + // commit may fail if other consumer gets the message on restart + Executors.newSingleThreadExecutor().execute(new Runnable() { + public void run() { + LOG.info("doing async commit..."); + try { + consumerSession.commit(); + } catch (JMSException ex) { + exceptions.add(ex); + } finally { + commitDone.countDown(); + } + } + }); + + + assertTrue("commit completed ", commitDone.await(15, TimeUnit.SECONDS)); + + // either message redelivered in existing tx or consumed by consumer2 + // should not be available again in any event + assertNull("consumer should not get rolled back on non redelivered message or duplicate", consumer.receive(5000)); + + // consumer replay is hashmap order dependent on a failover connection state recover so need to deal with both cases + if (exceptions.isEmpty()) { + LOG.info("commit succeeded, message was redelivered to the correct consumer after restart so commit was fine"); + assertNull("consumer2 not get a second message consumed by 1", consumer2.receive(2000)); + } else { + LOG.info("commit failed, consumer2 should get it", exceptions.get(0)); + assertNotNull("consumer2 got message", consumer2.receive(2000)); + consumerSession.commit(); + // no message should be in dlq + MessageConsumer dlqConsumer = consumerSession.createConsumer(consumerSession.createQueue("ActiveMQ.DLQ")); + assertNull("nothing in the dlq", dlqConsumer.receive(5000)); + } + connection.close(); + } + + private void produceMessage(final Session producerSession, Queue destination) + throws JMSException { + MessageProducer producer = producerSession.createProducer(destination); + TextMessage message = producerSession.createTextMessage("Test message"); + producer.send(message); + producer.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportBackupsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportBackupsTest.java new file mode 100644 index 0000000000..b1c8a1b43a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportBackupsTest.java @@ -0,0 +1,227 @@ +/** + * 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.transport.failover; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URI; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FailoverTransportBackupsTest { + + private static final Logger LOG = LoggerFactory.getLogger(FailoverTransportBackupsTest.class); + + protected Transport transport; + protected FailoverTransport failoverTransport; + private int transportInterruptions; + private int transportResumptions; + + BrokerService broker1; + BrokerService broker2; + BrokerService broker3; + + @Before + public void setUp() throws Exception { + broker1 = createBroker("1"); + broker2 = createBroker("2"); + broker3 = createBroker("3"); + + broker1.start(); + broker2.start(); + broker3.start(); + + broker1.waitUntilStarted(); + broker2.waitUntilStarted(); + broker3.waitUntilStarted(); + + // Reset stats + transportInterruptions = 0; + transportResumptions = 0; + } + + @After + public void tearDown() throws Exception { + if (transport != null) { + transport.stop(); + } + + broker1.stop(); + broker1.waitUntilStopped(); + broker2.stop(); + broker2.waitUntilStopped(); + broker3.stop(); + broker3.waitUntilStopped(); + } + + @Test + public void testBackupsAreCreated() throws Exception { + this.transport = createTransport(2); + assertNotNull(failoverTransport); + assertTrue(failoverTransport.isBackup()); + assertEquals(2, failoverTransport.getBackupPoolSize()); + + assertTrue("Timed out waiting for Backups to connect.", Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.debug("Current Backup Count = " + failoverTransport.getCurrentBackups()); + return failoverTransport.getCurrentBackups() == 2; + } + })); + } + + @Test + public void testFailoverToBackups() throws Exception { + this.transport = createTransport(2); + assertNotNull(failoverTransport); + assertTrue(failoverTransport.isBackup()); + assertEquals(2, failoverTransport.getBackupPoolSize()); + + assertTrue("Timed out waiting for Backups to connect.", Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.debug("Current Backup Count = " + failoverTransport.getCurrentBackups()); + return failoverTransport.getCurrentBackups() == 2; + } + })); + + broker1.stop(); + + assertTrue("Timed out waiting for Backups to connect.", Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.debug("Current Backup Count = " + failoverTransport.getCurrentBackups()); + return failoverTransport.getCurrentBackups() == 1; + } + })); + + assertTrue("Incorrect number of Transport interruptions", transportInterruptions >= 1); + assertTrue("Incorrect number of Transport resumptions", transportResumptions >= 1); + + broker2.stop(); + + assertTrue("Timed out waiting for Backups to connect.", Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.debug("Current Backup Count = " + failoverTransport.getCurrentBackups()); + return failoverTransport.getCurrentBackups() == 0; + } + })); + + assertTrue("Incorrect number of Transport interruptions", transportInterruptions >= 2); + assertTrue("Incorrect number of Transport resumptions", transportResumptions >= 2); + } + + @Test + public void testBackupsRefilled() throws Exception { + this.transport = createTransport(1); + assertNotNull(failoverTransport); + assertTrue(failoverTransport.isBackup()); + assertEquals(1, failoverTransport.getBackupPoolSize()); + + assertTrue("Timed out waiting for Backups to connect.", Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.debug("Current Backup Count = " + failoverTransport.getCurrentBackups()); + return failoverTransport.getCurrentBackups() == 1; + } + })); + + broker1.stop(); + + assertTrue("Timed out waiting for Backups to connect.", Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.debug("Current Backup Count = " + failoverTransport.getCurrentBackups()); + return failoverTransport.getCurrentBackups() == 1; + } + })); + + broker2.stop(); + + assertTrue("Timed out waiting for Backups to connect.", Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.debug("Current Backup Count = " + failoverTransport.getCurrentBackups()); + return failoverTransport.getCurrentBackups() == 0; + } + })); + } + + private BrokerService createBroker(String name) throws Exception { + BrokerService bs = new BrokerService(); + bs.setBrokerName(name); + bs.setUseJmx(false); + bs.setPersistent(false); + bs.addConnector("tcp://localhost:0"); + return bs; + } + + protected Transport createTransport(int backups) throws Exception { + String connectionUri = "failover://("+ + broker1.getTransportConnectors().get(0).getPublishableConnectString() + "," + + broker2.getTransportConnectors().get(0).getPublishableConnectString() + "," + + broker3.getTransportConnectors().get(0).getPublishableConnectString() + ")"; + + if (backups > 0) { + connectionUri += "?randomize=false&backup=true&backupPoolSize=" + backups; + } + + Transport transport = TransportFactory.connect(new URI(connectionUri)); + transport.setTransportListener(new TransportListener() { + + @Override + public void onCommand(Object command) { + LOG.debug("Test Transport Listener received Command: " + command); + } + + @Override + public void onException(IOException error) { + LOG.debug("Test Transport Listener received Exception: " + error); + } + + @Override + public void transportInterupted() { + transportInterruptions++; + LOG.debug("Test Transport Listener records transport Interrupted: " + transportInterruptions); + } + + @Override + public void transportResumed() { + transportResumptions++; + LOG.debug("Test Transport Listener records transport Resumed: " + transportResumptions); + } + }); + transport.start(); + + this.failoverTransport = transport.narrow(FailoverTransport.class); + + return transport; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportBrokerTest.java new file mode 100644 index 0000000000..575b594b4a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportBrokerTest.java @@ -0,0 +1,182 @@ +/** + * 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.transport.failover; + +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; + +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.network.NetworkTestSupport; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FailoverTransportBrokerTest extends NetworkTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(FailoverTransportBrokerTest.class); + + public ActiveMQDestination destination; + public int deliveryMode; + + public void initCombosForTestPublisherFailsOver() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST")}); + } + + public void testPublisherFailsOver() 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); + 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); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + // Start a failover publisher. + LOG.info("Starting the failover connection."); + StubConnection connection3 = createFailoverConnection(null); + ConnectionInfo connectionInfo3 = createConnectionInfo(); + SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); + ProducerInfo producerInfo3 = createProducerInfo(sessionInfo3); + connection3.send(connectionInfo3); + connection3.send(sessionInfo3); + connection3.send(producerInfo3); + + // Send the message using the fail over publisher. + connection3.request(createMessage(producerInfo3, destination, deliveryMode)); + + // The message will be sent to one of the brokers. + FailoverTransport ft = connection3.getTransport().narrow(FailoverTransport.class); + + // See which broker we were connected to. + StubConnection connectionA; + StubConnection connectionB; + TransportConnector serverA; + if (connector.getServer().getConnectURI().equals(ft.getConnectedTransportURI())) { + connectionA = connection1; + connectionB = connection2; + serverA = connector; + } else { + connectionA = connection2; + connectionB = connection1; + serverA = remoteConnector; + } + + assertNotNull(receiveMessage(connectionA)); + assertNoMessagesLeft(connectionB); + + // Dispose the server so that it fails over to the other server. + LOG.info("Disconnecting the active connection"); + serverA.stop(); + + connection3.request(createMessage(producerInfo3, destination, deliveryMode)); + + assertNotNull(receiveMessage(connectionB)); + assertNoMessagesLeft(connectionA); + + } + + public void testNoBrokersInBrokerInfo() throws Exception { + final BrokerInfo info[] = new BrokerInfo[1]; + TransportListener listener = new TransportListener() { + @Override + public void onCommand(Object command) { + LOG.info("Got command: " + command); + if (command instanceof BrokerInfo) { + info[0] = (BrokerInfo) command; + } + } + + @Override + public void onException(IOException error) { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void transportInterupted() { + //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public void transportResumed() { + //To change body of implemented methods use File | Settings | File Templates. + } + }; + @SuppressWarnings("unused") + StubConnection c = createFailoverConnection(listener); + int count = 0; + while(count++ < 20 && info[0] == null) { + TimeUnit.SECONDS.sleep(1); + } + assertNotNull("got a valid brokerInfo after 20 secs", info[0]); + assertNull("no peer brokers present", info[0].getPeerBrokerInfos()); + } + + @Override + protected String getLocalURI() { + return "tcp://localhost:0?wireFormat.tcpNoDelayEnabled=true"; + } + + @Override + protected String getRemoteURI() { + return "tcp://localhost:0?wireFormat.tcpNoDelayEnabled=true"; + } + + protected StubConnection createFailoverConnection(TransportListener listener) throws Exception { + URI failoverURI = new URI("failover://" + connector.getServer().getConnectURI() + "," + remoteConnector.getServer().getConnectURI() + ""); + Transport transport = TransportFactory.connect(failoverURI); + StubConnection connection = new StubConnection(transport, listener); + connections.add(connection); + return connection; + } + + public static Test suite() { + return suite(FailoverTransportBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportTest.java new file mode 100644 index 0000000000..fd130fcb77 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportTest.java @@ -0,0 +1,180 @@ +/** + * 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.transport.failover; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.URI; + +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.MessageAck; +import org.apache.activemq.command.RemoveInfo; +import org.apache.activemq.command.ShutdownInfo; +import org.apache.activemq.state.ConnectionStateTracker; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +public class FailoverTransportTest { + + protected Transport transport; + protected FailoverTransport failoverTransport; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + if (transport != null) { + transport.stop(); + } + } + + @Test(timeout = 30000) + @Ignore("Test fails on windows") + public void testReconnectUnlimited() throws Exception { + + Transport transport = TransportFactory.connect( + new URI("failover://(tcp://0.0.0.0:61616)?useExponentialBackOff=false&reconnectDelay=0&initialReconnectDelay=0")); + + transport.setTransportListener(new TransportListener() { + + public void onCommand(Object command) { + } + + public void onException(IOException error) { + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + transport.start(); + + this.failoverTransport = transport.narrow(FailoverTransport.class); + + assertTrue("no implicit limit of 1000", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return failoverTransport.getConnectFailures() > 1002; + } + })); + } + + @Test(timeout=30000) + public void testCommandsIgnoredWhenOffline() throws Exception { + this.transport = createTransport(); + + assertNotNull(failoverTransport); + + ConnectionStateTracker tracker = failoverTransport.getStateTracker(); + assertNotNull(tracker); + + ConnectionId id = new ConnectionId("1"); + ConnectionInfo connection = new ConnectionInfo(id); + + // Track a connection + tracker.track(connection); + try { + this.transport.oneway(new RemoveInfo(new ConnectionId("1"))); + } catch(Exception e) { + fail("Should not have failed to remove this known connection"); + } + + try { + this.transport.oneway(new RemoveInfo(new ConnectionId("2"))); + } catch(Exception e) { + fail("Should not have failed to remove this unknown connection"); + } + + this.transport.oneway(new MessageAck()); + this.transport.oneway(new ShutdownInfo()); + } + + @Test(timeout=30000) + public void testResponsesSentWhenRequestForIgnoredCommands() throws Exception { + this.transport = createTransport(); + assertNotNull(failoverTransport); + MessageAck ack = new MessageAck(); + assertNotNull("Should have received a Response", this.transport.request(ack)); + RemoveInfo info = new RemoveInfo(new ConnectionId("2")); + assertNotNull("Should have received a Response", this.transport.request(info)); + } + + @Test + public void testLocalhostPortSyntax() throws Exception { + transport = TransportFactory.connect( + new URI("failover://(tcp://localhost:1111/localhost:2111)")); + + transport.setTransportListener(new TransportListener() { + + public void onCommand(Object command) { + } + + public void onException(IOException error) { + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + + failoverTransport = transport.narrow(FailoverTransport.class); + + transport.start(); + + } + + protected Transport createTransport() throws Exception { + Transport transport = TransportFactory.connect( + new URI("failover://(tcp://localhost:1234?transport.connectTimeout=10000)")); + transport.setTransportListener(new TransportListener() { + + public void onCommand(Object command) { + } + + public void onException(IOException error) { + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + transport.start(); + + this.failoverTransport = transport.narrow(FailoverTransport.class); + + return transport; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportUriHandlingTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportUriHandlingTest.java new file mode 100644 index 0000000000..1258fbcad1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverTransportUriHandlingTest.java @@ -0,0 +1,146 @@ +/** + * 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.transport.failover; + +import static org.junit.Assert.*; + +import java.lang.reflect.Field; +import java.net.URI; +import java.util.Collection; + +import org.apache.activemq.transport.failover.FailoverTransport; +import org.junit.Test; + +public class FailoverTransportUriHandlingTest { + + @Test + public void testFailoverTransportAddWithInitialUnknown() throws Exception { + FailoverTransport transport = new FailoverTransport(); + + final String initialUri = "tcp://no.existing.hostname:61616"; + + transport.add(false, initialUri); + + String[] uriArray = new String[] {"tcp://127.0.0.2:61616", + "tcp://localhost:61616", + "tcp://localhost:61617"}; + + for(String uri : uriArray) { + transport.add(false, uri); + } + + Collection uris = getRegisteredUrlsFromPrivateField(transport); + + for(String uri : uriArray) { + assertTrue("Collection should contain: " + uri, uris.contains(new URI(uri))); + } + } + + @Test + public void testFailoverTransportAddWithInitialKnown() throws Exception { + FailoverTransport transport = new FailoverTransport(); + + final String initialUri = "tcp://localhost:61616"; + + transport.add(false, initialUri); + + String[] uriArray = new String[] {"tcp://127.0.0.2:61616", + "tcp://no.existing.hostname:61616", + "tcp://localhost:61617"}; + + for(String uri : uriArray) { + transport.add(false, uri); + } + + Collection uris = getRegisteredUrlsFromPrivateField(transport); + + for(String uri : uriArray) { + assertTrue("Collection should contain: " + uri, uris.contains(new URI(uri))); + } + } + + @Test + public void testFailoverTransportAddWithPreventsDups() throws Exception { + FailoverTransport transport = new FailoverTransport(); + + final String initialUri = "tcp://localhost:61616"; + + transport.add(false, initialUri); + + String[] uriArray = new String[] {"tcp://127.0.0.2:61616", + "tcp://localhost:61616", + "tcp://no.existing.hostname:61616", + "tcp://localhost:61617", + "tcp://127.0.0.1:61616"}; + + for(String uri : uriArray) { + transport.add(false, uri); + } + + Collection uris = getRegisteredUrlsFromPrivateField(transport); + + assertEquals(4, uris.size()); + + // Ensure even the unknowns get checked. + transport.add(false, "tcp://no.existing.hostname:61616"); + + uris = getRegisteredUrlsFromPrivateField(transport); + + assertEquals(4, uris.size()); + } + + @Test + public void testFailoverTransportAddArray() throws Exception { + FailoverTransport transport = new FailoverTransport(); + + final String initialUri = "tcp://no.existing.hostname:61616"; + + transport.add(false, initialUri); + + URI[] uriArray = new URI[] {new URI("tcp://127.0.0.2:61616"), + new URI("tcp://localhost:61616"), + new URI("tcp://localhost:61617")}; + + transport.add(false, uriArray); + + Collection uris = getRegisteredUrlsFromPrivateField(transport); + + for(URI uri : uriArray) { + assertTrue("Collection should contain: " + uri, uris.contains(uri)); + } + + assertEquals(4, uris.size()); + + // Ensure even the unknowns get checked. + transport.add(false, "tcp://no.existing.hostname:61616"); + + uris = getRegisteredUrlsFromPrivateField(transport); + + assertEquals(4, uris.size()); + + transport.add(false, uriArray); + + assertEquals(4, uris.size()); + } + + @SuppressWarnings("unchecked") + private Collection getRegisteredUrlsFromPrivateField(FailoverTransport failoverTransport) throws SecurityException, NoSuchFieldException, IllegalAccessException { + Field urisField = failoverTransport.getClass().getDeclaredField("uris"); + urisField.setAccessible(true); + return (Collection) urisField.get(failoverTransport); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUpdateURIsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUpdateURIsTest.java new file mode 100644 index 0000000000..9c9b2fd978 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUpdateURIsTest.java @@ -0,0 +1,156 @@ +/** + * 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.transport.failover; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +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.network.NetworkConnector; +import org.apache.log4j.Logger; + +public class FailoverUpdateURIsTest extends TestCase { + + private static final String QUEUE_NAME = "test.failoverupdateuris"; + private static final Logger LOG = Logger.getLogger(FailoverUpdateURIsTest.class); + + String firstTcpUri = "tcp://localhost:61616"; + String secondTcpUri = "tcp://localhost:61626"; + Connection connection = null; + BrokerService bs1 = null; + BrokerService bs2 = null; + + @Override + public void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + if (bs1 != null) { + bs1.stop(); + } + if (bs2 != null) { + bs2.stop(); + } + } + + public void testUpdateURIsViaFile() throws Exception { + + String targetDir = "target/" + getName(); + new File(targetDir).mkdir(); + File updateFile = new File(targetDir + "/updateURIsFile.txt"); + LOG.info(updateFile); + LOG.info(updateFile.toURI()); + LOG.info(updateFile.getAbsoluteFile()); + LOG.info(updateFile.getAbsoluteFile().toURI()); + 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()); + 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"); + producer.send(message); + Message msg = consumer.receive(2000); + assertNotNull(msg); + + bs1.stop(); + bs1.waitUntilStopped(); + bs1 = null; + + bs2 = createBroker("bs2", secondTcpUri); + bs2.start(); + + // add the transport uri for broker number 2 + out = new FileOutputStream(updateFile, true); + out.write(",".getBytes()); + out.write(secondTcpUri.toString().getBytes()); + out.close(); + + producer.send(message); + msg = consumer.receive(2000); + assertNotNull(msg); + } + + private BrokerService createBroker(String name, String tcpUri) throws Exception { + BrokerService bs = new BrokerService(); + bs.setBrokerName(name); + bs.setUseJmx(false); + bs.setPersistent(false); + bs.addConnector(tcpUri); + return bs; + } + + public void testAutoUpdateURIs() throws Exception { + + bs1 = new BrokerService(); + bs1.setUseJmx(false); + TransportConnector transportConnector = bs1.addConnector(firstTcpUri); + transportConnector.setUpdateClusterClients(true); + bs1.start(); + + 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"); + producer.send(message); + Message msg = consumer.receive(4000); + assertNotNull(msg); + + bs2 = createBroker("bs2", secondTcpUri); + NetworkConnector networkConnector = bs2.addNetworkConnector("static:(" + firstTcpUri + ")"); + networkConnector.setDuplex(true); + bs2.start(); + LOG.info("started brokerService 2"); + bs2.waitUntilStarted(); + + TimeUnit.SECONDS.sleep(4); + + LOG.info("stopping brokerService 1"); + bs1.stop(); + bs1.waitUntilStopped(); + bs1 = null; + + producer.send(message); + msg = consumer.receive(4000); + assertNotNull(msg); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUriTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUriTest.java new file mode 100644 index 0000000000..01a8966e0c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUriTest.java @@ -0,0 +1,48 @@ +/** + * 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.transport.failover; + +import junit.framework.Test; + +import org.apache.activemq.transport.tcp.TransportUriTest; + +public class FailoverUriTest extends TransportUriTest { + + @Override + public void initCombosForTestUriOptionsWork() { + addCombinationValues("prefix", new Object[]{"failover:(", "failover://("}); + addCombinationValues("postfix", new Object[] {")?initialReconnectDelay=1000&maxReconnectDelay=1000" + , "?wireFormat.tightEncodingEnabled=false)?jms.useAsyncSend=true&jms.copyMessageOnSend=false" + , "?wireFormat.maxInactivityDuration=0&keepAlive=true)?jms.prefetchPolicy.all=500&initialReconnectDelay=10000&useExponentialBackOff=false&maxReconnectAttempts=0&randomize=false"}); + } + + @Override + public void initCombosForTestBadVersionNumberDoesNotWork() { + addCombinationValues("prefix", new Object[]{"failover:("}); + addCombinationValues("postfix", new Object[] {")?initialReconnectDelay=1000&maxReconnectDelay=1000"}); + } + + @Override + public void initCombosForTestBadPropertyNameFails() { + addCombinationValues("prefix", new Object[]{"failover:("}); + addCombinationValues("postfix", new Object[] {")?initialReconnectDelay=1000&maxReconnectDelay=1000"}); + } + + public static Test suite() { + return suite(FailoverUriTest.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/InitalReconnectDelayTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/InitalReconnectDelayTest.java new file mode 100644 index 0000000000..8fe8c08f53 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/InitalReconnectDelayTest.java @@ -0,0 +1,187 @@ +/** + * 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.transport.failover; + +import java.io.IOException; +import java.util.Date; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.transport.TransportListener; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.*; + +public class InitalReconnectDelayTest { + + private static final transient Logger LOG = LoggerFactory.getLogger(InitalReconnectDelayTest.class); + protected BrokerService broker1; + protected BrokerService broker2; + + @Test + public void testInitialReconnectDelay() throws Exception { + + String uriString = "failover://(tcp://localhost:" + + broker1.getTransportConnectors().get(0).getConnectUri().getPort() + + ",tcp://localhost:" + + broker2.getTransportConnectors().get(0).getConnectUri().getPort() + + ")?randomize=false&initialReconnectDelay=15000"; + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(uriString); + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue("foo"); + MessageProducer producer = session.createProducer(destination); + + long start = (new Date()).getTime(); + producer.send(session.createTextMessage("TEST")); + long end = (new Date()).getTime(); + + //Verify we can send quickly + assertTrue((end - start) < 2000); + + //Halt the broker1... + LOG.info("Stopping the Broker1..."); + start = (new Date()).getTime(); + broker1.stop(); + + LOG.info("Attempting to send... failover should kick in..."); + producer.send(session.createTextMessage("TEST")); + end = (new Date()).getTime(); + + //Inital reconnection should kick in and be darned close to what we expected + LOG.info("Failover took " + (end - start) + " ms."); + assertTrue("Failover took " + (end - start) + " ms and should be > 14000.", (end - start) > 14000); + } + + @Test + public void testNoSuspendedCallbackOnNoReconnect() throws Exception { + + String uriString = "failover://(tcp://localhost:" + + broker1.getTransportConnectors().get(0).getConnectUri().getPort() + + ",tcp://localhost:" + + broker2.getTransportConnectors().get(0).getConnectUri().getPort() + + ")?randomize=false&maxReconnectAttempts=0"; + + + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(uriString); + final AtomicInteger calls = new AtomicInteger(0); + connectionFactory.setTransportListener(new TransportListener() { + @Override + public void onCommand(Object command) { + } + + @Override + public void onException(IOException error) { + LOG.info("on exception: " + error); + calls.set(0x01 | calls.intValue()); + } + + @Override + public void transportInterupted() { + LOG.info("on transportInterupted"); + calls.set(0x02 | calls.intValue()); + } + + @Override + public void transportResumed() { + LOG.info("on transportResumed"); + calls.set(0x04 | calls.intValue()); + } + }); + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue("foo"); + MessageProducer producer = session.createProducer(destination); + + final Message message = session.createTextMessage("TEST"); + producer.send(message); + + // clear listener state + calls.set(0); + + LOG.info("Stopping the Broker1..."); + broker1.stop(); + + LOG.info("Attempting to send... failover should throw on disconnect"); + try { + producer.send(destination, message); + fail("Expect IOException to bubble up on send"); + } catch (javax.jms.IllegalStateException producerClosed) { + } + + assertEquals("Only an exception is reported to the listener", 0x1, calls.get()); + } + + @Before + public void setUp() throws Exception { + + final String dataDir = "target/data/shared"; + + broker1 = new BrokerService(); + + broker1.setBrokerName("broker1"); + broker1.setDeleteAllMessagesOnStartup(true); + broker1.setDataDirectory(dataDir); + broker1.addConnector("tcp://localhost:0"); + broker1.setUseJmx(false); + broker1.start(); + broker1.waitUntilStarted(); + + broker2 = new BrokerService(); + broker2.setBrokerName("broker2"); + broker2.setDataDirectory(dataDir); + broker2.setUseJmx(false); + broker2.addConnector("tcp://localhost:0"); + broker2.start(); + broker2.waitUntilStarted(); + + } + + protected String getSlaveXml() { + return "org/apache/activemq/broker/ft/sharedFileSlave.xml"; + } + + protected String getMasterXml() { + return "org/apache/activemq/broker/ft/sharedFileMaster.xml"; + } + + @After + public void tearDown() throws Exception { + + if (broker1.isStarted()) { + broker1.stop(); + broker1.waitUntilStopped(); + } + + if (broker2.isStarted()) { + broker2.stop(); + broker2.waitUntilStopped(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/ReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/ReconnectTest.java new file mode 100644 index 0000000000..28031578e0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/ReconnectTest.java @@ -0,0 +1,232 @@ +/** + * 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.transport.failover; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnection; +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.transport.TransportListener; +import org.apache.activemq.transport.mock.MockTransport; +import org.apache.activemq.util.ServiceStopper; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReconnectTest extends TestCase { + + public static final int MESSAGES_PER_ITTERATION = 10; + public static final int WORKER_COUNT = 10; + + private static final Logger LOG = LoggerFactory.getLogger(ReconnectTest.class); + + private BrokerService bs; + private URI tcpUri; + private final AtomicInteger resumedCount = new AtomicInteger(); + private final AtomicInteger interruptedCount = new AtomicInteger(); + private Worker[] workers; + + class Worker implements Runnable { + + public AtomicInteger iterations = new AtomicInteger(); + public CountDownLatch stopped = new CountDownLatch(1); + + private final ActiveMQConnection connection; + private final AtomicBoolean stop = new AtomicBoolean(false); + private Throwable error; + private final String name; + + public Worker(final String name) throws URISyntaxException, JMSException { + this.name = name; + URI uri = new URI("failover://(mock://(" + tcpUri + "))?updateURIsSupported=false"); + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(uri); + connection = (ActiveMQConnection) factory.createConnection(); + connection.addTransportListener(new TransportListener() { + public void onCommand(Object command) { + } + + public void onException(IOException error) { + setError(error); + } + + public void transportInterupted() { + LOG.info("Worker " + name + " was interrupted..."); + interruptedCount.incrementAndGet(); + } + + public void transportResumed() { + LOG.info("Worker " + name + " was resummed..."); + resumedCount.incrementAndGet(); + } + }); + connection.start(); + } + + public void failConnection() { + MockTransport mockTransport = connection.getTransportChannel().narrow(MockTransport.class); + mockTransport.onException(new IOException("Simulated error")); + } + + public void start() { + new Thread(this).start(); + } + + public void stop() { + stop.set(true); + try { + if (!stopped.await(5, TimeUnit.SECONDS)) { + connection.close(); + stopped.await(5, TimeUnit.SECONDS); + } else { + connection.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void run() { + try { + ActiveMQQueue queue = new ActiveMQQueue("FOO_" + name); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + while (!stop.get()) { + for (int i = 0; i < MESSAGES_PER_ITTERATION; i++) { + producer.send(session.createTextMessage("TEST:" + i)); + } + for (int i = 0; i < MESSAGES_PER_ITTERATION; i++) { + consumer.receive(); + } + iterations.incrementAndGet(); + } + session.close(); + } catch (JMSException e) { + setError(e); + } finally { + stopped.countDown(); + } + } + + public synchronized Throwable getError() { + return error; + } + + public synchronized void setError(Throwable error) { + this.error = error; + } + + public synchronized void assertNoErrors() { + if (error != null) { + error.printStackTrace(); + fail("Worker " + name + " got Exception: " + error); + } + } + } + + public void testReconnects() throws Exception { + + for (int k = 1; k < 10; k++) { + LOG.info("Test run: " + k); + + // Wait for at least one iteration to occur... + for (int i = 0; i < WORKER_COUNT; i++) { + int c = 0; + for (int j = 0; j < 30; j++) { + c = workers[i].iterations.getAndSet(0); + if (c != 0) { + break; + } + workers[i].assertNoErrors(); + LOG.info("Test run " + k + ": Waiting for worker " + i + " to finish an iteration."); + Thread.sleep(1000); + } + assertTrue("Test run " + k + ": Worker " + i + " never completed an interation.", c != 0); + workers[i].assertNoErrors(); + } + + LOG.info("Simulating transport error to cause reconnect."); + + // Simulate a transport failure. + for (int i = 0; i < WORKER_COUNT; i++) { + workers[i].failConnection(); + } + + assertTrue("Timed out waiting for all connections to be interrupted.", Wait.waitFor(new Wait.Condition(){ + public boolean isSatisified() throws Exception { + LOG.debug("Test run waiting for connections to get interrupted.. at: " + interruptedCount.get()); + return interruptedCount.get() == WORKER_COUNT; + } + }, TimeUnit.SECONDS.toMillis(60))); + + // Wait for the connections to re-establish... + assertTrue("Timed out waiting for all connections to be resumed.", Wait.waitFor(new Wait.Condition(){ + public boolean isSatisified() throws Exception { + LOG.debug("Test run waiting for connections to get resumed.. at: " + resumedCount.get()); + return resumedCount.get() >= WORKER_COUNT; + } + }, TimeUnit.SECONDS.toMillis(60))); + + // Reset the counters.. + interruptedCount.set(0); + resumedCount.set(0); + for (int i = 0; i < WORKER_COUNT; i++) { + workers[i].iterations.set(0); + } + + Thread.sleep(1000); + } + } + + @Override + protected void setUp() throws Exception { + bs = new BrokerService(); + bs.setPersistent(false); + bs.setUseJmx(true); + TransportConnector connector = bs.addConnector("tcp://localhost:0"); + bs.start(); + tcpUri = connector.getConnectUri(); + workers = new Worker[WORKER_COUNT]; + for (int i = 0; i < WORKER_COUNT; i++) { + workers[i] = new Worker("" + i); + workers[i].start(); + } + } + + @Override + protected void tearDown() throws Exception { + for (int i = 0; i < WORKER_COUNT; i++) { + workers[i].stop(); + } + new ServiceStopper().stop(bs); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/SlowConnectionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/SlowConnectionTest.java new file mode 100644 index 0000000000..357e0fbcb7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/SlowConnectionTest.java @@ -0,0 +1,99 @@ +/** + * 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.transport.failover; + +import java.io.IOException; +import java.net.*; +import java.util.*; +import java.util.concurrent.CountDownLatch; + +import javax.jms.Connection; +import javax.net.ServerSocketFactory; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.util.Wait; + +public class SlowConnectionTest extends TestCase { + + private CountDownLatch socketReadyLatch = new CountDownLatch(1); + + public void testSlowConnection() throws Exception { + + MockBroker broker = new MockBroker(); + broker.start(); + + socketReadyLatch.await(); + int timeout = 1000; + URI tcpUri = new URI("tcp://localhost:" + broker.ss.getLocalPort() + "?soTimeout=" + timeout + "&trace=true&connectionTimeout=" + timeout + "&wireFormat.maxInactivityDurationInitalDelay=" + timeout); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + tcpUri + ")"); + final Connection connection = cf.createConnection(); + + new Thread(new Runnable() { + public void run() { + try { connection.start(); } catch (Throwable ignored) {} + } + }).start(); + + int count = 0; + assertTrue("Transport count: " + count + ", expected <= 1", Wait.waitFor(new Wait.Condition(){ + public boolean isSatisified() throws Exception { + int count = 0; + for (Thread thread : Thread.getAllStackTraces().keySet()) { + if (thread.getName().contains("ActiveMQ Transport")) { count++; } + } + return count == 1; + }})); + + broker.interrupt(); + broker.join(); + } + + class MockBroker extends Thread { + ServerSocket ss = null; + public MockBroker() { + super("MockBroker"); + } + + public void run() { + + List inProgress = new ArrayList(); + ServerSocketFactory factory = ServerSocketFactory.getDefault(); + + try { + ss = factory.createServerSocket(0); + ss.setSoTimeout(5000); + + socketReadyLatch.countDown(); + while (!interrupted()) { + inProgress.add(ss.accept()); // eat socket + } + } catch (java.net.SocketTimeoutException expected) { + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { ss.close(); } catch (IOException ignored) {} + for (Socket s : inProgress) { + try { s.close(); } catch (IOException ignored) {} + } + } + } + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/TwoBrokerFailoverClusterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/TwoBrokerFailoverClusterTest.java new file mode 100644 index 0000000000..19addc3305 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/failover/TwoBrokerFailoverClusterTest.java @@ -0,0 +1,92 @@ +/** + * 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.transport.failover; + +public class TwoBrokerFailoverClusterTest 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_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_A_NAME = "BROKERA"; + private static final String BROKER_B_NAME = "BROKERB"; + + public void testTwoBrokersRestart() throws Exception { + createBrokerA(false, "", null, null); + createBrokerB(false, "", null, null); + getBroker(BROKER_B_NAME).waitUntilStarted(); + + Thread.sleep(2000); + setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + createClients(); + + Thread.sleep(5000); + + assertClientsConnectedToTwoBrokers(); + assertClientsConnectionsEvenlyDistributed(.35); + + + getBroker(BROKER_A_NAME).stop(); + getBroker(BROKER_A_NAME).waitUntilStopped(); + removeBroker(BROKER_A_NAME); + + Thread.sleep(1000); + + assertAllConnectedTo(BROKER_B_CLIENT_TC_ADDRESS); + + Thread.sleep(5000); + + createBrokerA(false, "", null, null); + getBroker(BROKER_A_NAME).waitUntilStarted(); + Thread.sleep(5000); + + assertClientsConnectedToTwoBrokers(); + assertClientsConnectionsEvenlyDistributed(.35); + } + + + private void createBrokerA(boolean multi, String params, String clusterFilter, String destinationFilter) throws Exception { + final String tcParams = (params == null)?"":params; + if (getBroker(BROKER_A_NAME) == null) { + 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); + } else { + addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); + } + 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); + 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); + } else { + addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); + } + getBroker(BROKER_B_NAME).start(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTest.java new file mode 100644 index 0000000000..62104d49de --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTest.java @@ -0,0 +1,97 @@ +/** + * 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.transport.fanout; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +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; + +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; + + 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.start(); + broker2.start(); + + broker1.waitUntilStarted(); + broker2.waitUntilStarted(); + + 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(); + for (int i = 0; i < messageCount; i++) { + Message msg = producerSession.createTextMessage("Message " + i); + prod.send(msg); + } + prod.close(); + + assertMessagesReceived("tcp://localhost:61616"); + assertMessagesReceived("tcp://localhost:61617"); + + } + + protected MessageProducer createProducer() throws Exception { + return producerSession.createProducer(producerSession.createQueue("TEST")); + } + + protected void assertMessagesReceived(String brokerURL) throws Exception { + ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory(brokerURL); + 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(); + consumer.setMessageListener(listener); + listener.waitForMessagesToArrive(messageCount); + listener.assertMessagesReceived(messageCount); + + consumer.close(); consumerConnection.close(); consumerSession.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTransportBrokerTest.java new file mode 100644 index 0000000000..f8236f51f9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTransportBrokerTest.java @@ -0,0 +1,203 @@ +/** + * 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.transport.fanout; + +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.DeliveryMode; + +import junit.framework.Test; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.network.NetworkTestSupport; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportFilter; +import org.apache.activemq.transport.mock.MockTransport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FanoutTransportBrokerTest extends NetworkTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(FanoutTransportBrokerTest.class); + + public ActiveMQDestination destination; + public int deliveryMode; + + public static Test suite() { + return suite(FanoutTransportBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void initCombosForTestPublisherFansout() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destination", new Object[] {new ActiveMQTopic("TEST"), new ActiveMQQueue("TEST")}); + } + + 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); + 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); + 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); + connection3.send(connectionInfo3); + connection3.send(sessionInfo3); + connection3.send(producerInfo3); + + // Send the message using the fail over publisher. + connection3.request(createMessage(producerInfo3, destination, deliveryMode)); + + assertNotNull(receiveMessage(connection1)); + assertNoMessagesLeft(connection1); + + assertNotNull(receiveMessage(connection2)); + assertNoMessagesLeft(connection2); + + } + + public void initCombosForTestPublisherWaitsForServerToBeUp() { + addCombinationValues("deliveryMode", new Object[] {Integer.valueOf(DeliveryMode.NON_PERSISTENT), Integer.valueOf(DeliveryMode.PERSISTENT)}); + addCombinationValues("destination", new Object[] {new ActiveMQTopic("TEST")}); + } + + 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); + 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); + connection2.send(connectionInfo2); + connection2.send(sessionInfo2); + connection2.request(consumerInfo2); + + // Start a fanout publisher. + LOG.info("Starting the fanout connection."); + final StubConnection connection3 = createFanoutConnection(); + ConnectionInfo connectionInfo3 = createConnectionInfo(); + SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); + final ProducerInfo producerInfo3 = createProducerInfo(sessionInfo3); + connection3.send(connectionInfo3); + connection3.send(sessionInfo3); + connection3.send(producerInfo3); + + // Send the message using the fail over publisher. + connection3.request(createMessage(producerInfo3, destination, deliveryMode)); + + assertNotNull(receiveMessage(connection1)); + assertNoMessagesLeft(connection1); + + assertNotNull(receiveMessage(connection2)); + assertNoMessagesLeft(connection2); + + final CountDownLatch publishDone = new CountDownLatch(1); + + // The MockTransport is on the remote connection. + // Slip in a new transport filter after the MockTransport + 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); + // just eat it! to simulate a recent failure. + } + }); + + // Send a message (async) as this will block + new Thread() { + public void run() { + // Send the message using the fail over publisher. + try { + connection3.request(createMessage(producerInfo3, destination, deliveryMode)); + } catch (Throwable e) { + e.printStackTrace(); + } + publishDone.countDown(); + } + }.start(); + + // Assert that we block: + assertFalse(publishDone.await(3, TimeUnit.SECONDS)); + + // Restart the remote server. State should be re-played and the publish + // should continue. + LOG.info("Restarting Broker"); + restartRemoteBroker(); + LOG.info("Broker Restarted"); + + // This should reconnect, and resend + assertTrue(publishDone.await(20, TimeUnit.SECONDS)); + + } + + protected String getLocalURI() { + return "tcp://localhost:61616"; + } + + protected String getRemoteURI() { + return "tcp://localhost:61617"; + } + + 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); + connections.add(connection); + return connection; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/multicast/MulticastTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/multicast/MulticastTransportTest.java new file mode 100644 index 0000000000..a4ca8a2c57 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/multicast/MulticastTransportTest.java @@ -0,0 +1,71 @@ +/** + * 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.transport.multicast; + +import java.net.URI; + +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.CommandJoiner; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.udp.UdpTransportTest; +import org.apache.activemq.util.IntSequenceGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class MulticastTransportTest extends UdpTransportTest { + + private static final Logger LOG = LoggerFactory.getLogger(MulticastTransportTest.class); + + private String multicastURI = "multicast://224.1.2.3:6255"; + + + protected Transport createProducer() throws Exception { + LOG.info("Producer using URI: " + multicastURI); + + // we are not using the TransportFactory as this assumes that + // transports talk to a server using a WireFormat Negotiation step + // rather than talking directly to each other + + OpenWireFormat wireFormat = createWireFormat(); + MulticastTransport transport = new MulticastTransport(wireFormat, new URI(multicastURI)); + transport.setLoopBackMode(false); + transport.setSequenceGenerator(new IntSequenceGenerator()); + return new CommandJoiner(transport, wireFormat); + } + + protected Transport createConsumer() throws Exception { + OpenWireFormat wireFormat = createWireFormat(); + MulticastTransport transport = new MulticastTransport(wireFormat, new URI(multicastURI)); + transport.setLoopBackMode(false); + transport.setSequenceGenerator(new IntSequenceGenerator()); + return new CommandJoiner(transport, wireFormat); + } + + @Override + public void testSendingMediumMessage() throws Exception { + // Ignoring, see AMQ-4973 + } + + @Override + public void testSendingLargeMessage() throws Exception { + // Ignoring, see AMQ-4973 + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOJmsDurableTopicSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOJmsDurableTopicSendReceiveTest.java new file mode 100644 index 0000000000..84f955e2bb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOJmsDurableTopicSendReceiveTest.java @@ -0,0 +1,56 @@ +/** + * 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.transport.nio; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsDurableTopicSendReceiveTest; +import org.apache.activemq.broker.BrokerService; + +public class NIOJmsDurableTopicSendReceiveTest extends JmsDurableTopicSendReceiveTest { + protected BrokerService broker; + + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + broker.start(); + } + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(getBrokerURL()); + return connectionFactory; + } + + protected String getBrokerURL() { + return "nio://localhost:61616"; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.addConnector(getBrokerURL()); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOJmsSendAndReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOJmsSendAndReceiveTest.java new file mode 100644 index 0000000000..0f1032cfe8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOJmsSendAndReceiveTest.java @@ -0,0 +1,59 @@ +/** + * 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.transport.nio; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; + +/** + * + */ +public class NIOJmsSendAndReceiveTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + protected BrokerService broker; + + protected void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + broker.start(); + } + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(getBrokerURL()); + return connectionFactory; + } + + protected String getBrokerURL() { + return "nio://localhost:61616"; + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.addConnector(getBrokerURL()); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOPersistentSendAndReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOPersistentSendAndReceiveTest.java new file mode 100644 index 0000000000..330557f907 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOPersistentSendAndReceiveTest.java @@ -0,0 +1,38 @@ +/** + * 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.transport.nio; + +import javax.jms.DeliveryMode; + +import org.apache.activemq.broker.BrokerService; + +public class NIOPersistentSendAndReceiveTest extends NIOJmsSendAndReceiveTest { + protected BrokerService broker; + + protected void setUp() throws Exception { + this.topic = false; + this.deliveryMode = DeliveryMode.PERSISTENT; + super.setUp(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(true); + answer.addConnector(getBrokerURL()); + return answer; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLBasicTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLBasicTest.java new file mode 100644 index 0000000000..885446df88 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLBasicTest.java @@ -0,0 +1,115 @@ +/** + * 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.transport.nio; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class NIOSSLBasicTest { + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/org/apache/activemq/security/broker1.ks"; + public static final String TRUST_KEYSTORE = "src/test/resources/org/apache/activemq/security/broker1.ks"; + + public static final int MESSAGE_COUNT = 1000; + + @Before + public void before() throws Exception { + System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStore", SERVER_KEYSTORE); + System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + // Choose a value that's informative: ssl,handshake,data,trustmanager or all + //System.setProperty("javax.net.debug", "handshake"); + } + + @After + public void after() throws Exception { + } + + public BrokerService createBroker(String connectorName, String connectorString) throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + TransportConnector connector = broker.addConnector(connectorString); + connector.setName(connectorName); + broker.start(); + broker.waitUntilStarted(); + return broker; + } + + public void stopBroker(BrokerService broker) throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test + public void basicConnector() throws Exception { + BrokerService broker = createBroker("nio+ssl", "nio+ssl://localhost:0?transport.needClientAuth=true"); + basicSendReceive("ssl://localhost:" + broker.getConnectorByName("nio+ssl").getConnectUri().getPort()); + stopBroker(broker); + } + + @Test + public void enabledCipherSuites() throws Exception { + BrokerService broker = createBroker("nio+ssl", "nio+ssl://localhost:0?transport.needClientAuth=true&transport.enabledCipherSuites=SSL_RSA_WITH_RC4_128_SHA,SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"); + basicSendReceive("ssl://localhost:" + broker.getConnectorByName("nio+ssl").getConnectUri().getPort()); + stopBroker(broker); + } + + @Test + public void enabledProtocols() throws Exception { + BrokerService broker = createBroker("nio+ssl", "nio+ssl://localhost:61616?transport.needClientAuth=true&transport.enabledProtocols=TLSv1,TLSv1.1,TLSv1.2"); + basicSendReceive("ssl://localhost:" + broker.getConnectorByName("nio+ssl").getConnectUri().getPort()); + stopBroker(broker); + } + + public void basicSendReceive(String uri) throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(uri); + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.start(); + + String body = "hello world!"; + Queue destination = session.createQueue("TEST"); + MessageProducer producer = session.createProducer(destination); + producer.send(session.createTextMessage(body)); + + MessageConsumer consumer = session.createConsumer(destination); + Message received = consumer.receive(2000); + TestCase.assertEquals(body, ((TextMessage)received).getText()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLConcurrencyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLConcurrencyTest.java new file mode 100644 index 0000000000..1ade5165c0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLConcurrencyTest.java @@ -0,0 +1,251 @@ +/** + * 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.transport.nio; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +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.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@SuppressWarnings({ "javadoc" }) +public class NIOSSLConcurrencyTest extends TestCase { + + BrokerService broker; + Connection connection; + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/server.keystore"; + public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore"; + + public static final int PRODUCER_COUNT = 10; + public static final int CONSUMER_COUNT = 10; + public static final int MESSAGE_COUNT = 10000; + public static final int MESSAGE_SIZE = 4096; + + final ConsumerThread[] consumers = new ConsumerThread[CONSUMER_COUNT]; + final Session[] producerSessions = new Session[PRODUCER_COUNT]; + final Session[] consumerSessions = new Session[CONSUMER_COUNT]; + + byte[] messageData; + volatile boolean failed; + + @Override + protected void setUp() throws Exception { + System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStore", SERVER_KEYSTORE); + System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + TransportConnector connector = broker.addConnector("nio+ssl://localhost:0?transport.needClientAuth=true&transport.enabledCipherSuites=SSL_RSA_WITH_RC4_128_SHA,SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"); + broker.start(); + broker.waitUntilStarted(); + + failed = false; + messageData = new byte[MESSAGE_SIZE]; + for (int i = 0; i < MESSAGE_SIZE; i++) + { + messageData[i] = (byte) (i & 0xff); + } + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("nio+ssl://localhost:" + connector.getConnectUri().getPort()); + connection = factory.createConnection(); + + for (int i = 0; i < PRODUCER_COUNT; i++) { + producerSessions[i] = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + for (int i = 0; i < CONSUMER_COUNT; i++) { + consumerSessions[i] = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + connection.start(); + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + public void testLoad() throws Exception { + for (int i = 0; i < PRODUCER_COUNT; i++) { + Queue dest = producerSessions[i].createQueue("TEST" + i); + ProducerThread producer = new ProducerThread(producerSessions[i], dest); + producer.setMessageCount(MESSAGE_COUNT); + producer.start(); + } + + for (int i = 0; i < CONSUMER_COUNT; i++) { + Queue dest = consumerSessions[i].createQueue("TEST" + i); + ConsumerThread consumer = new ConsumerThread(consumerSessions[i], dest); + consumer.setMessageCount(MESSAGE_COUNT); + consumer.start(); + consumers[i] = consumer; + } + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return failed || getReceived() == PRODUCER_COUNT * MESSAGE_COUNT; + } + }, 120000); + + assertEquals(PRODUCER_COUNT * MESSAGE_COUNT, getReceived()); + + } + + protected int getReceived() { + int received = 0; + for (ConsumerThread consumer : consumers) { + received += consumer.getReceived(); + } + return received; + } + + private class ConsumerThread extends Thread { + + private final Logger LOG = LoggerFactory.getLogger(ConsumerThread.class); + + int messageCount = 1000; + int received = 0; + Destination dest; + Session sess; + boolean breakOnNull = true; + + public ConsumerThread(Session sess, Destination dest) { + this.dest = dest; + this.sess = sess; + } + + @Override + public void run() { + MessageConsumer consumer = null; + + try { + consumer = sess.createConsumer(dest); + while (received < messageCount) { + Message msg = consumer.receive(3000); + if (msg != null) { + LOG.info("Received test message: " + received++); + } else { + if (breakOnNull) { + break; + } + } + } + } catch (JMSException e) { + e.printStackTrace(); + failed = true; + } finally { + if (consumer != null) { + try { + consumer.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + } + + public int getReceived() { + return received; + } + + public void setMessageCount(int messageCount) { + this.messageCount = messageCount; + } + } + + private class ProducerThread extends Thread { + + private final Logger LOG = LoggerFactory.getLogger(ProducerThread.class); + + int messageCount = 1000; + Destination dest; + protected Session sess; + int sleep = 0; + int sentCount = 0; + + public ProducerThread(Session sess, Destination dest) { + this.dest = dest; + this.sess = sess; + } + + @Override + public void run() { + MessageProducer producer = null; + try { + producer = sess.createProducer(dest); + for (sentCount = 0; sentCount < messageCount; sentCount++) { + producer.send(createMessage(sentCount)); + LOG.info("Sent 'test message: " + sentCount + "'"); + if (sleep > 0) { + Thread.sleep(sleep); + } + } + } catch (Exception e) { + e.printStackTrace(); + failed = true; + } finally { + if (producer != null) { + try { + producer.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + } + + protected Message createMessage(int i) throws Exception { + BytesMessage b = sess.createBytesMessage(); + b.writeBytes(messageData); + return b; + } + + public void setMessageCount(int messageCount) { + this.messageCount = messageCount; + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLLoadTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLLoadTest.java new file mode 100644 index 0000000000..698945c614 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLLoadTest.java @@ -0,0 +1,115 @@ +/** + * 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.transport.nio; + +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.util.ConsumerThread; +import org.apache.activemq.util.ProducerThread; +import org.apache.activemq.util.Wait; + +import javax.jms.Connection; +import javax.jms.Queue; +import javax.jms.Session; + +public class NIOSSLLoadTest extends TestCase { + + BrokerService broker; + Connection connection; + Session session; + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/server.keystore"; + public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore"; + + public static final int PRODUCER_COUNT = 10; + public static final int CONSUMER_COUNT = 10; + public static final int MESSAGE_COUNT = 1000; + + final ConsumerThread[] consumers = new ConsumerThread[CONSUMER_COUNT]; + + @Override + protected void setUp() throws Exception { + System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStore", SERVER_KEYSTORE); + System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + TransportConnector connector = broker.addConnector("nio+ssl://localhost:0?transport.needClientAuth=true&transport.enabledCipherSuites=SSL_RSA_WITH_RC4_128_SHA,SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"); + broker.start(); + broker.waitUntilStarted(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("nio+ssl://localhost:" + connector.getConnectUri().getPort()); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.start(); + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + public void testLoad() throws Exception { + Queue dest = session.createQueue("TEST"); + for (int i = 0; i < PRODUCER_COUNT; i++) { + ProducerThread producer = new ProducerThread(session, dest); + producer.setMessageCount(MESSAGE_COUNT); + producer.start(); + } + + for (int i = 0; i < CONSUMER_COUNT; i++) { + ConsumerThread consumer = new ConsumerThread(session, dest); + consumer.setMessageCount(MESSAGE_COUNT); + consumer.start(); + consumers[i] = consumer; + } + + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return getReceived() == PRODUCER_COUNT * MESSAGE_COUNT; + } + }, 60000); + + assertEquals(PRODUCER_COUNT * MESSAGE_COUNT, getReceived()); + + } + + protected int getReceived() { + int received = 0; + for (ConsumerThread consumer : consumers) { + received += consumer.getReceived(); + } + return received; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLTransportBrokerTest.java new file mode 100644 index 0000000000..33735407bd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLTransportBrokerTest.java @@ -0,0 +1,67 @@ +/** + * 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.transport.nio; + +import java.net.URI; +import java.net.URISyntaxException; +import junit.framework.Test; +import junit.textui.TestRunner; +import org.apache.activemq.transport.TransportBrokerTestSupport; + +public class NIOSSLTransportBrokerTest extends TransportBrokerTestSupport { + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/server.keystore"; + public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore"; + + protected String getBindLocation() { + return "nio+ssl://localhost:0?transport.soWriteTimeout=20000"; + } + + @Override + protected URI getBindURI() throws URISyntaxException { + return new URI("nio+ssl://localhost:0?soWriteTimeout=20000"); + } + + protected void setUp() throws Exception { + System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStore", SERVER_KEYSTORE); + System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + //System.setProperty("javax.net.debug", "ssl,handshake,data,trustmanager"); + + maxWait = 10000; + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public static Test suite() { + return suite(NIOSSLTransportBrokerTest.class); + } + + public static void main(String[] args) { + TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLWindowSizeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLWindowSizeTest.java new file mode 100644 index 0000000000..17cdc415f2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOSSLWindowSizeTest.java @@ -0,0 +1,113 @@ +/** + * 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.transport.nio; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +@SuppressWarnings("javadoc") +public class NIOSSLWindowSizeTest extends TestCase { + + BrokerService broker; + Connection connection; + Session session; + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/server.keystore"; + public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore"; + + public static final int PRODUCER_COUNT = 1; + public static final int CONSUMER_COUNT = 1; + public static final int MESSAGE_COUNT = 1; + public static final int MESSAGE_SIZE = 65536; + + byte[] messageData; + + @Override + protected void setUp() throws Exception { + System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStore", SERVER_KEYSTORE); + System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + + broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + TransportConnector connector = broker.addConnector("nio+ssl://localhost:0?transport.needClientAuth=true"); + broker.start(); + broker.waitUntilStarted(); + + messageData = new byte[MESSAGE_SIZE]; + for (int i = 0; i < MESSAGE_SIZE; i++) + { + messageData[i] = (byte) (i & 0xff); + } + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("nio+ssl://localhost:" + connector.getConnectUri().getPort()); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + connection.start(); + } + + @Override + protected void tearDown() throws Exception { + if (session != null) { + session.close(); + } + if (connection != null) { + connection.close(); + } + + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + public void testLargePayload() throws Exception { + Queue dest = session.createQueue("TEST"); + MessageProducer prod = null; + try { + prod = session.createProducer(dest); + BytesMessage msg = session.createBytesMessage(); + msg.writeBytes(messageData); + prod.send(msg); + } finally { + prod.close(); + } + MessageConsumer cons = null; + try + { + cons = session.createConsumer(dest); + assertNotNull(cons.receive(30000L)); + } finally { + cons.close(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOTransportBrokerTest.java new file mode 100644 index 0000000000..ea103873e3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/nio/NIOTransportBrokerTest.java @@ -0,0 +1,37 @@ +/** + * 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.transport.nio; + +import junit.framework.Test; +import junit.textui.TestRunner; +import org.apache.activemq.transport.TransportBrokerTestSupport; + +public class NIOTransportBrokerTest extends TransportBrokerTestSupport { + + protected String getBindLocation() { + return "nio://localhost:61616"; + } + + public static Test suite() { + return suite(NIOTransportBrokerTest.class); + } + + public static void main(String[] args) { + TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/peer/PeerTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/peer/PeerTransportTest.java new file mode 100644 index 0000000000..4ac3dd4dd0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/peer/PeerTransportTest.java @@ -0,0 +1,157 @@ +/** + * 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.transport.peer; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class PeerTransportTest extends TestCase { + protected static final int MESSAGE_COUNT = 50; + protected static final int NUMBER_IN_CLUSTER = 3; + private static final Logger LOG = LoggerFactory.getLogger(PeerTransportTest.class); + + protected ActiveMQDestination destination; + protected boolean topic = true; + protected int deliveryMode = DeliveryMode.NON_PERSISTENT; + protected MessageProducer[] producers; + protected Connection[] connections; + protected MessageIdList messageIdList[]; + + @Override + protected void setUp() throws Exception { + + connections = new Connection[NUMBER_IN_CLUSTER]; + producers = new MessageProducer[NUMBER_IN_CLUSTER]; + messageIdList = new MessageIdList[NUMBER_IN_CLUSTER]; + ActiveMQDestination destination = createDestination(); + + for (int i = 0; i < NUMBER_IN_CLUSTER; i++) { + connections[i] = createConnection(i); + connections[i].setClientID("ClusterTest" + i); + connections[i].start(); + + Session session = connections[i].createSession(false, Session.AUTO_ACKNOWLEDGE); + producers[i] = session.createProducer(destination); + producers[i].setDeliveryMode(deliveryMode); + MessageConsumer consumer = createMessageConsumer(session, destination); + messageIdList[i] = new MessageIdList(); + consumer.setMessageListener(messageIdList[i]); + } + + LOG.info("Waiting for cluster to be fully connected"); + + // Each connection should see that NUMBER_IN_CLUSTER consumers get + // registered on the destination. + ActiveMQDestination advisoryDest = AdvisorySupport.getConsumerAdvisoryTopic(destination); + for (int i = 0; i < NUMBER_IN_CLUSTER; i++) { + Session session = connections[i].createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = createMessageConsumer(session, advisoryDest); + + int j = 0; + while (j < NUMBER_IN_CLUSTER) { + ActiveMQMessage message = (ActiveMQMessage)consumer.receive(1000); + if (message == null) { + fail("Connection " + i + " saw " + j + " consumers, expected: " + NUMBER_IN_CLUSTER); + } + if (message.getDataStructure() != null && message.getDataStructure().getDataStructureType() == ConsumerInfo.DATA_STRUCTURE_TYPE) { + j++; + } + } + + session.close(); + } + + LOG.info("Cluster is online."); + } + + @Override + protected void tearDown() throws Exception { + if (connections != null) { + for (int i = 0; i < connections.length; i++) { + connections[i].close(); + } + } + } + + protected MessageConsumer createMessageConsumer(Session session, Destination destination) throws JMSException { + return session.createConsumer(destination); + } + + protected Connection createConnection(int i) throws JMSException { + LOG.info("creating connection ...."); + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory("peer://" + getClass().getName() + "/node" + i); + return fac.createConnection(); + } + + protected ActiveMQDestination createDestination() { + return createDestination(getClass().getName()); + } + + protected ActiveMQDestination createDestination(String name) { + if (topic) { + return new ActiveMQTopic(name); + } else { + return new ActiveMQQueue(name); + } + } + + /** + * @throws Exception + */ + public void testSendReceive() throws Exception { + for (int i = 0; i < MESSAGE_COUNT; i++) { + for (int x = 0; x < producers.length; x++) { + TextMessage textMessage = new ActiveMQTextMessage(); + textMessage.setText("MSG-NO: " + i + " in cluster: " + x); + producers[x].send(textMessage); + } + } + + for (int i = 0; i < NUMBER_IN_CLUSTER; i++) { + messageIdList[i].assertMessagesReceived(expectedReceiveCount()); + } + } + + protected int expectedReceiveCount() { + return MESSAGE_COUNT * NUMBER_IN_CLUSTER; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/DropCommandStrategy.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/DropCommandStrategy.java new file mode 100644 index 0000000000..f35ed7e85b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/DropCommandStrategy.java @@ -0,0 +1,33 @@ +/** + * 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.transport.reliable; + +import java.net.SocketAddress; + +/** + * + * + */ +public interface DropCommandStrategy { + + /** + * Returns true if the command should be dropped for + * the given command ID and address + */ + boolean shouldDropCommand(int commandId, SocketAddress address, boolean redelivery); + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/ReliableTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/ReliableTransportTest.java new file mode 100644 index 0000000000..4f00e06251 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/ReliableTransportTest.java @@ -0,0 +1,133 @@ +/** + * 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.transport.reliable; + +import java.util.Queue; + +import junit.framework.TestCase; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.transport.StubTransport; +import org.apache.activemq.transport.StubTransportListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ReliableTransportTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ReliableTransportTest.class); + + protected ReliableTransport transport; + protected StubTransportListener listener = new StubTransportListener(); + protected ReplayStrategy replayStrategy; + + public void testValidSequenceOfPackets() throws Exception { + int[] sequenceNumbers = {1, 2, 3, 4, 5, 6, 7}; + + sendStreamOfCommands(sequenceNumbers, true); + } + + public void testValidWrapAroundPackets() throws Exception { + int[] sequenceNumbers = new int[10]; + + int value = Integer.MAX_VALUE - 3; + transport.setExpectedCounter(value); + + for (int i = 0; i < 10; i++) { + LOG.info("command: " + i + " = " + value); + sequenceNumbers[i] = value++; + } + + sendStreamOfCommands(sequenceNumbers, true); + } + + public void testDuplicatePacketsDropped() throws Exception { + int[] sequenceNumbers = {1, 2, 2, 3, 4, 5, 6, 7}; + + sendStreamOfCommands(sequenceNumbers, true, 7); + } + + public void testOldDuplicatePacketsDropped() throws Exception { + int[] sequenceNumbers = {1, 2, 3, 4, 5, 2, 6, 7}; + + sendStreamOfCommands(sequenceNumbers, true, 7); + } + + public void testOldDuplicatePacketsDroppedUsingNegativeCounters() throws Exception { + int[] sequenceNumbers = {-3, -1, -3, -2, -1, 0, 1, -1, 3, 2, 0, 2, 4}; + + transport.setExpectedCounter(-3); + + sendStreamOfCommands(sequenceNumbers, true, 8); + } + + public void testWrongOrderOfPackets() throws Exception { + int[] sequenceNumbers = {4, 3, 1, 5, 2, 7, 6, 8, 10, 9}; + + sendStreamOfCommands(sequenceNumbers, true); + } + + public void testMissingPacketsFails() throws Exception { + int[] sequenceNumbers = {1, 2, /* 3, */4, 5, 6, 7, 8, 9, 10}; + + sendStreamOfCommands(sequenceNumbers, false); + } + + protected void sendStreamOfCommands(int[] sequenceNumbers, boolean expected) { + sendStreamOfCommands(sequenceNumbers, expected, sequenceNumbers.length); + } + + protected void sendStreamOfCommands(int[] sequenceNumbers, boolean expected, int expectedCount) { + for (int i = 0; i < sequenceNumbers.length; i++) { + int commandId = sequenceNumbers[i]; + + ConsumerInfo info = new ConsumerInfo(); + info.setSelector("Cheese: " + commandId); + info.setCommandId(commandId); + + transport.onCommand(info); + } + + Queue exceptions = listener.getExceptions(); + Queue commands = listener.getCommands(); + if (expected) { + if (!exceptions.isEmpty()) { + Exception e = (Exception)exceptions.remove(); + e.printStackTrace(); + fail("Caught exception: " + e); + } + assertEquals("number of messages received", expectedCount, commands.size()); + + assertEquals("Should have no buffered commands", 0, transport.getBufferedCommandCount()); + } else { + assertTrue("Should have received an exception!", exceptions.size() > 0); + Exception e = (Exception)exceptions.remove(); + LOG.info("Caught expected response: " + e); + } + } + + protected void setUp() throws Exception { + if (replayStrategy == null) { + replayStrategy = new ExceptionIfDroppedReplayStrategy(); + } + transport = new ReliableTransport(new StubTransport(), replayStrategy); + transport.setTransportListener(listener); + transport.start(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableCommandDatagramChannel.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableCommandDatagramChannel.java new file mode 100644 index 0000000000..0acf5c3231 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableCommandDatagramChannel.java @@ -0,0 +1,59 @@ +/** + * 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.transport.reliable; + +import java.io.IOException; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; + +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.udp.ByteBufferPool; +import org.apache.activemq.transport.udp.CommandDatagramChannel; +import org.apache.activemq.transport.udp.DatagramHeaderMarshaller; +import org.apache.activemq.transport.udp.UdpTransport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class UnreliableCommandDatagramChannel extends CommandDatagramChannel { + + private static final Logger LOG = LoggerFactory.getLogger(UnreliableCommandDatagramChannel.class); + + private DropCommandStrategy dropCommandStrategy; + + public UnreliableCommandDatagramChannel(UdpTransport transport, OpenWireFormat wireFormat, int datagramSize, SocketAddress targetAddress, + DatagramHeaderMarshaller headerMarshaller, ReplayBuffer replayBuffer, DatagramChannel channel, ByteBufferPool bufferPool, + DropCommandStrategy strategy) { + super(transport, wireFormat, datagramSize, targetAddress, headerMarshaller, channel, bufferPool); + this.dropCommandStrategy = strategy; + } + + protected void sendWriteBuffer(int commandId, SocketAddress address, ByteBuffer writeBuffer, boolean redelivery) throws IOException { + if (dropCommandStrategy.shouldDropCommand(commandId, address, redelivery)) { + writeBuffer.flip(); + LOG.info("Dropping datagram with command: " + commandId); + + // lets still add it to the replay buffer though! + getReplayBuffer().addBuffer(commandId, writeBuffer); + } else { + super.sendWriteBuffer(commandId, address, writeBuffer, redelivery); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableCommandDatagramSocket.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableCommandDatagramSocket.java new file mode 100644 index 0000000000..2d599031be --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableCommandDatagramSocket.java @@ -0,0 +1,57 @@ +/** + * 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.transport.reliable; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.SocketAddress; + +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.udp.CommandDatagramSocket; +import org.apache.activemq.transport.udp.DatagramHeaderMarshaller; +import org.apache.activemq.transport.udp.UdpTransport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class UnreliableCommandDatagramSocket extends CommandDatagramSocket { + private static final Logger LOG = LoggerFactory.getLogger(UnreliableCommandDatagramSocket.class); + + private DropCommandStrategy dropCommandStrategy; + + public UnreliableCommandDatagramSocket(UdpTransport transport, OpenWireFormat wireFormat, int datagramSize, SocketAddress targetAddress, + DatagramHeaderMarshaller headerMarshaller, DatagramSocket channel, DropCommandStrategy strategy) { + super(transport, wireFormat, datagramSize, targetAddress, headerMarshaller, channel); + this.dropCommandStrategy = strategy; + } + + protected void sendWriteBuffer(int commandId, SocketAddress address, byte[] data, boolean redelivery) throws IOException { + if (dropCommandStrategy.shouldDropCommand(commandId, address, redelivery)) { + LOG.info("Dropping datagram with command: " + commandId); + + // lets still add it to the replay buffer though! + ReplayBuffer bufferCache = getReplayBuffer(); + if (bufferCache != null && !redelivery) { + bufferCache.addBuffer(commandId, data); + } + } else { + super.sendWriteBuffer(commandId, address, data, redelivery); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableUdpTransport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableUdpTransport.java new file mode 100644 index 0000000000..cd969d49d9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableUdpTransport.java @@ -0,0 +1,68 @@ +/** + * 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.transport.reliable; + +import java.io.IOException; +import java.net.SocketAddress; +import java.net.URI; +import java.net.UnknownHostException; + +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.udp.CommandChannel; +import org.apache.activemq.transport.udp.UdpTransport; + +/** + * An unreliable UDP transport that will randomly discard packets to simulate a + * bad network (or UDP buffers being flooded). + * + * + */ +public class UnreliableUdpTransport extends UdpTransport { + + private DropCommandStrategy dropCommandStrategy; + + public UnreliableUdpTransport(OpenWireFormat wireFormat, int port) throws UnknownHostException, IOException { + super(wireFormat, port); + } + + public UnreliableUdpTransport(OpenWireFormat wireFormat, SocketAddress socketAddress) throws IOException { + super(wireFormat, socketAddress); + } + + public UnreliableUdpTransport(OpenWireFormat wireFormat, URI remoteLocation) throws UnknownHostException, + IOException { + super(wireFormat, remoteLocation); + } + + public UnreliableUdpTransport(OpenWireFormat wireFormat) throws IOException { + super(wireFormat); + } + + public DropCommandStrategy getDropCommandStrategy() { + return dropCommandStrategy; + } + + public void setDropCommandStrategy(DropCommandStrategy dropCommandStrategy) { + this.dropCommandStrategy = dropCommandStrategy; + } + + protected CommandChannel createCommandDatagramChannel() { + return new UnreliableCommandDatagramChannel(this, getWireFormat(), getDatagramSize(), getTargetAddress(), + createDatagramHeaderMarshaller(), getReplayBuffer(), getChannel(), getBufferPool(), dropCommandStrategy); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableUdpTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableUdpTransportTest.java new file mode 100644 index 0000000000..3ac406acc0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/reliable/UnreliableUdpTransportTest.java @@ -0,0 +1,92 @@ +/** + * 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.transport.reliable; + +import java.net.SocketAddress; +import java.net.URI; + +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.CommandJoiner; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.udp.ResponseRedirectInterceptor; +import org.apache.activemq.transport.udp.UdpTransport; +import org.apache.activemq.transport.udp.UdpTransportTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class UnreliableUdpTransportTest extends UdpTransportTest { + private static final Logger LOG = LoggerFactory.getLogger(UnreliableUdpTransportTest.class); + + protected DropCommandStrategy dropStrategy = new DropCommandStrategy() { + + @Override + public boolean shouldDropCommand(int commandId, SocketAddress address, boolean redelivery) { + if (redelivery) { + return false; + } + return commandId % 3 == 2; + } + }; + + @Override + protected Transport createProducer() throws Exception { + LOG.info("Producer using URI: " + producerURI); + + OpenWireFormat wireFormat = createWireFormat(); + UnreliableUdpTransport transport = new UnreliableUdpTransport(wireFormat, new URI(producerURI)); + transport.setDropCommandStrategy(dropStrategy); + + ReliableTransport reliableTransport = new ReliableTransport(transport, transport); + Replayer replayer = reliableTransport.getReplayer(); + reliableTransport.setReplayStrategy(createReplayStrategy(replayer)); + + return new CommandJoiner(reliableTransport, wireFormat); + } + + @Override + protected Transport createConsumer() throws Exception { + LOG.info("Consumer on port: " + consumerPort); + OpenWireFormat wireFormat = createWireFormat(); + UdpTransport transport = new UdpTransport(wireFormat, consumerPort); + + ReliableTransport reliableTransport = new ReliableTransport(transport, transport); + Replayer replayer = reliableTransport.getReplayer(); + reliableTransport.setReplayStrategy(createReplayStrategy(replayer)); + + ResponseRedirectInterceptor redirectInterceptor = new ResponseRedirectInterceptor(reliableTransport, transport); + return new CommandJoiner(redirectInterceptor, wireFormat); + } + + protected ReplayStrategy createReplayStrategy(Replayer replayer) { + assertNotNull("Should have a replayer!", replayer); + return new DefaultReplayStrategy(1); + } + + @Override + public void testSendingMediumMessage() throws Exception { + // Ignoring, see AMQ-4973 + } + + @Override + public void testSendingLargeMessage() throws Exception { + // Ignoring, see AMQ-4973 + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/InactivityMonitorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/InactivityMonitorTest.java new file mode 100644 index 0000000000..919c5daf21 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/InactivityMonitorTest.java @@ -0,0 +1,255 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.net.SocketFactory; + +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.command.WireFormatInfo; +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportAcceptListener; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.transport.TransportServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class InactivityMonitorTest extends CombinationTestSupport implements TransportAcceptListener { + private static final Logger LOG = LoggerFactory.getLogger(InactivityMonitorTest.class); + + public Runnable serverRunOnCommand; + public Runnable clientRunOnCommand; + + private TransportServer server; + private Transport clientTransport; + private Transport serverTransport; + private int serverPort; + + private final AtomicInteger clientReceiveCount = new AtomicInteger(0); + private final AtomicInteger clientErrorCount = new AtomicInteger(0); + private final AtomicInteger serverReceiveCount = new AtomicInteger(0); + private final AtomicInteger serverErrorCount = new AtomicInteger(0); + + private final AtomicBoolean ignoreClientError = new AtomicBoolean(false); + private final AtomicBoolean ignoreServerError = new AtomicBoolean(false); + + protected void setUp() throws Exception { + super.setUp(); + startTransportServer(); + } + + /** + * @throws Exception + * @throws URISyntaxException + */ + private void startClient() throws Exception, URISyntaxException { + clientTransport = TransportFactory.connect(new URI("tcp://localhost:" + serverPort + "?trace=true&wireFormat.maxInactivityDuration=1000")); + clientTransport.setTransportListener(new TransportListener() { + public void onCommand(Object command) { + clientReceiveCount.incrementAndGet(); + if (clientRunOnCommand != null) { + clientRunOnCommand.run(); + } + } + + public void onException(IOException error) { + if (!ignoreClientError.get()) { + LOG.info("Client transport error:"); + error.printStackTrace(); + clientErrorCount.incrementAndGet(); + } + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + clientTransport.start(); + } + + /** + * @throws IOException + * @throws URISyntaxException + * @throws Exception + */ + private void startTransportServer() throws IOException, URISyntaxException, Exception { + server = TransportFactory.bind(new URI("tcp://localhost:0?trace=true&wireFormat.maxInactivityDuration=1000")); + server.setAcceptListener(this); + server.start(); + + serverPort = server.getSocketAddress().getPort(); + } + + protected void tearDown() throws Exception { + ignoreClientError.set(true); + ignoreServerError.set(true); + try { + if (clientTransport != null) { + clientTransport.stop(); + } + if (serverTransport != null) { + serverTransport.stop(); + } + if (server != null) { + server.stop(); + } + } catch (Throwable e) { + e.printStackTrace(); + } + super.tearDown(); + } + + public void onAccept(Transport transport) { + try { + LOG.info("[" + getName() + "] Server Accepted a Connection"); + serverTransport = transport; + serverTransport.setTransportListener(new TransportListener() { + public void onCommand(Object command) { + serverReceiveCount.incrementAndGet(); + if (serverRunOnCommand != null) { + serverRunOnCommand.run(); + } + } + + public void onException(IOException error) { + if (!ignoreClientError.get()) { + LOG.info("Server transport error:", error); + serverErrorCount.incrementAndGet(); + } + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + serverTransport.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void onAcceptError(Exception error) { + LOG.trace(error.toString()); + } + + public void testClientHang() throws Exception { + + // + // Manually create a client transport so that it does not send KeepAlive + // packets. + // this should simulate a client hang. + clientTransport = new TcpTransport(new OpenWireFormat(), SocketFactory.getDefault(), new URI("tcp://localhost:" + serverPort), null); + clientTransport.setTransportListener(new TransportListener() { + public void onCommand(Object command) { + clientReceiveCount.incrementAndGet(); + if (clientRunOnCommand != null) { + clientRunOnCommand.run(); + } + } + + public void onException(IOException error) { + if (!ignoreClientError.get()) { + LOG.info("Client transport error:"); + error.printStackTrace(); + clientErrorCount.incrementAndGet(); + } + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + clientTransport.start(); + WireFormatInfo info = new WireFormatInfo(); + info.setVersion(OpenWireFormat.DEFAULT_VERSION); + info.setMaxInactivityDuration(1000); + clientTransport.oneway(info); + + assertEquals(0, serverErrorCount.get()); + assertEquals(0, clientErrorCount.get()); + + // Server should consider the client timed out right away since the + // client is not hart beating fast enough. + Thread.sleep(6000); + + assertEquals(0, clientErrorCount.get()); + assertTrue(serverErrorCount.get() > 0); + } + + public void testNoClientHang() throws Exception { + startClient(); + + assertEquals(0, serverErrorCount.get()); + assertEquals(0, clientErrorCount.get()); + + Thread.sleep(4000); + + assertEquals(0, clientErrorCount.get()); + assertEquals(0, serverErrorCount.get()); + } + + /** + * Used to test when a operation blocks. This should not cause transport to + * get disconnected. + * + * @throws Exception + * @throws URISyntaxException + */ + public void initCombosForTestNoClientHangWithServerBlock() throws Exception { + + startClient(); + + addCombinationValues("clientInactivityLimit", new Object[] {Long.valueOf(1000)}); + addCombinationValues("serverInactivityLimit", new Object[] {Long.valueOf(1000)}); + addCombinationValues("serverRunOnCommand", new Object[] {new Runnable() { + public void run() { + try { + LOG.info("Sleeping"); + Thread.sleep(4000); + } catch (InterruptedException e) { + } + } + }}); + } + + public void testNoClientHangWithServerBlock() throws Exception { + + startClient(); + + assertEquals(0, serverErrorCount.get()); + assertEquals(0, clientErrorCount.get()); + + Thread.sleep(4000); + + assertEquals(0, clientErrorCount.get()); + assertEquals(0, serverErrorCount.get()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/QualityOfServiceUtilsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/QualityOfServiceUtilsTest.java new file mode 100644 index 0000000000..ec619a0fb4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/QualityOfServiceUtilsTest.java @@ -0,0 +1,170 @@ +/** + * 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.transport.tcp; + +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +public class QualityOfServiceUtilsTest extends TestCase { + /** + * Keeps track of the value that the System has set for the ECN bits, which + * should not be overridden when Differentiated Services is set, but may be + * overridden when Type of Service is set. + */ + private int ECN; + + @Override + protected void setUp() throws Exception { + Socket socket = new Socket(); + ECN = socket.getTrafficClass() & Integer.parseInt("00000011", 2); + socket.close(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testValidDiffServIntegerValues() { + int[] values = {0, 1, 32, 62, 63}; + for (int val : values) { + testValidDiffServIntegerValue(val); + } + } + + public void testInvalidDiffServIntegerValues() { + int[] values = {-2, -1, 64, 65}; + for (int val : values) { + testInvalidDiffServIntegerValue(val); + } + } + + public void testValidDiffServNames() { + Map namesToExpected = new HashMap(); + namesToExpected.put("CS0", Integer.valueOf("000000", 2)); + namesToExpected.put("CS1", Integer.valueOf("001000", 2)); + namesToExpected.put("CS2", Integer.valueOf("010000", 2)); + namesToExpected.put("CS3", Integer.valueOf("011000", 2)); + namesToExpected.put("CS4", Integer.valueOf("100000", 2)); + namesToExpected.put("CS5", Integer.valueOf("101000", 2)); + namesToExpected.put("CS6", Integer.valueOf("110000", 2)); + namesToExpected.put("CS7", Integer.valueOf("111000", 2)); + namesToExpected.put("EF", Integer.valueOf("101110", 2)); + namesToExpected.put("AF11", Integer.valueOf("001010", 2)); + namesToExpected.put("AF12", Integer.valueOf("001100", 2)); + namesToExpected.put("AF13", Integer.valueOf("001110", 2)); + namesToExpected.put("AF21", Integer.valueOf("010010", 2)); + namesToExpected.put("AF22", Integer.valueOf("010100", 2)); + namesToExpected.put("AF23", Integer.valueOf("010110", 2)); + namesToExpected.put("AF31", Integer.valueOf("011010", 2)); + namesToExpected.put("AF32", Integer.valueOf("011100", 2)); + namesToExpected.put("AF33", Integer.valueOf("011110", 2)); + namesToExpected.put("AF41", Integer.valueOf("100010", 2)); + namesToExpected.put("AF42", Integer.valueOf("100100", 2)); + namesToExpected.put("AF43", Integer.valueOf("100110", 2)); + for (String name : namesToExpected.keySet()) { + testValidDiffServName(name, namesToExpected.get(name)); + } + } + + public void testInvalidDiffServNames() { + String[] names = {"hello_world", "", "abcd"}; + for (String name : names) { + testInvalidDiffServName(name); + } + } + + private void testValidDiffServName(String name, int expected) { + int dscp = -1; + try { + dscp = QualityOfServiceUtils.getDSCP(name); + } catch (IllegalArgumentException e) { + fail("IllegalArgumentException thrown for valid Differentiated " + + " Services name: " + name); + } + // Make sure it adjusted for any system ECN values. + assertEquals("Incorrect Differentiated Services Code Point " + dscp + + " returned for name " + name + ".", ECN | (expected << 2), dscp); + } + + private void testInvalidDiffServName(String name) { + try { + QualityOfServiceUtils.getDSCP(name); + fail("No IllegalArgumentException thrown for invalid Differentiated" + + " Services value: " + name + "."); + } catch (IllegalArgumentException e) { + } + } + + private void testValidDiffServIntegerValue(int val) { + try { + int dscp = QualityOfServiceUtils.getDSCP(Integer.toString(val)); + // Make sure it adjusted for any system ECN values. + assertEquals("Incorrect Differentiated Services Code Point " + + "returned for value " + val + ".", ECN | (val << 2), dscp); + } catch (IllegalArgumentException e) { + fail("IllegalArgumentException thrown for valid Differentiated " + + "Services value " + val); + } + } + + private void testInvalidDiffServIntegerValue(int val) { + try { + QualityOfServiceUtils.getDSCP(Integer.toString(val)); + fail("No IllegalArgumentException thrown for invalid " + + "Differentiated Services value " + val + "."); + } catch (IllegalArgumentException expected) { + } + } + + public void testValidTypeOfServiceValues() { + int[] values = {0, 1, 32, 100, 255}; + for (int val : values) { + testValidTypeOfServiceValue(val); + } + } + + public void testInvalidTypeOfServiceValues() { + int[] values = {-2, -1, 256, 257}; + for (int val : values) { + testInvalidTypeOfServiceValue(val); + } + } + + private void testValidTypeOfServiceValue(int val) { + try { + int typeOfService = QualityOfServiceUtils.getToS(val); + assertEquals("Incorrect Type of Services value returned for " + val + + ".", val, typeOfService); + } catch (IllegalArgumentException e) { + fail("IllegalArgumentException thrown for valid Type of Service " + + "value " + val + "."); + } + } + + private void testInvalidTypeOfServiceValue(int val) { + try { + QualityOfServiceUtils.getToS(val); + fail("No IllegalArgumentException thrown for invalid " + + "Type of Service value " + val + "."); + } catch (IllegalArgumentException expected) { + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/ServerSocketTstFactory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/ServerSocketTstFactory.java new file mode 100644 index 0000000000..5b6adf6d0a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/ServerSocketTstFactory.java @@ -0,0 +1,81 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.util.Random; +import javax.net.ServerSocketFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + */ +public class ServerSocketTstFactory extends ServerSocketFactory { + private static final Logger LOG = LoggerFactory.getLogger(ServerSocketTstFactory.class); + + private class ServerSocketTst { + + private final ServerSocket socket; + + public ServerSocketTst(int port, Random rnd) throws IOException { + this.socket = ServerSocketFactory.getDefault().createServerSocket(port); + } + + public ServerSocketTst(int port, int backlog, Random rnd) throws IOException { + this.socket = ServerSocketFactory.getDefault().createServerSocket(port, backlog); + } + + public ServerSocketTst(int port, int backlog, InetAddress bindAddr, Random rnd) throws IOException { + this.socket = ServerSocketFactory.getDefault().createServerSocket(port, backlog, bindAddr); + } + + public ServerSocket getSocket() { + return this.socket; + } + }; + + private final Random rnd; + + public ServerSocketTstFactory() { + super(); + LOG.info("Creating a new ServerSocketTstFactory"); + this.rnd = new Random(); + } + + public ServerSocket createServerSocket(int port) throws IOException { + ServerSocketTst sSock = new ServerSocketTst(port, this.rnd); + return sSock.getSocket(); + } + + public ServerSocket createServerSocket(int port, int backlog) throws IOException { + ServerSocketTst sSock = new ServerSocketTst(port, backlog, this.rnd); + return sSock.getSocket(); + } + + public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { + ServerSocketTst sSock = new ServerSocketTst(port, backlog, ifAddress, this.rnd); + return sSock.getSocket(); + } + + private final static ServerSocketTstFactory server = new ServerSocketTstFactory(); + + public static ServerSocketTstFactory getDefault() { + return server; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SocketTstFactory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SocketTstFactory.java new file mode 100644 index 0000000000..396f284785 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SocketTstFactory.java @@ -0,0 +1,178 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; + +import javax.net.SocketFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + * Automatically generated socket.close() calls to simulate network faults + */ +public class SocketTstFactory extends SocketFactory { + private static final Logger LOG = LoggerFactory.getLogger(SocketTstFactory.class); + + private static final ConcurrentHashMap closeIter = new ConcurrentHashMap(); + + private class SocketTst { + + private class Bagot implements Runnable { + private final Thread processus; + private final Socket socket; + private final InetAddress address; + + public Bagot(Random rnd, Socket socket, InetAddress address) { + this.processus = new Thread(this, "Network Faults maker : undefined"); + this.socket = socket; + this.address = address; + } + + public void start() { + this.processus.setName("Network Faults maker : " + this.socket.toString()); + this.processus.start(); + } + + @Override + public void run() { + int lastDelayVal; + Integer lastDelay; + while (!this.processus.isInterrupted()) { + if (!this.socket.isClosed()) { + try { + lastDelay = closeIter.get(this.address); + if (lastDelay == null) { + lastDelayVal = 0; + } else { + lastDelayVal = lastDelay.intValue(); + if (lastDelayVal > 10) + lastDelayVal += 20; + else + lastDelayVal += 1; + } + + lastDelay = new Integer(lastDelayVal); + + LOG.info("Trying to close client socket " + socket.toString() + " in " + lastDelayVal + " milliseconds"); + + try { + Thread.sleep(lastDelayVal); + } catch (InterruptedException e) { + this.processus.interrupt(); + Thread.currentThread().interrupt(); + } catch (IllegalArgumentException e) { + } + + this.socket.close(); + closeIter.put(this.address, lastDelay); + LOG.info("Client socket " + this.socket.toString() + " is closed."); + } catch (IOException e) { + } + } + + this.processus.interrupt(); + } + } + } + + private final Bagot bagot; + private final Socket socket; + + public SocketTst(InetAddress address, int port, Random rnd) throws IOException { + this.socket = new Socket(address, port); + bagot = new Bagot(rnd, this.socket, address); + } + + public SocketTst(InetAddress address, int port, InetAddress localAddr, int localPort, Random rnd) throws IOException { + this.socket = new Socket(address, port, localAddr, localPort); + bagot = new Bagot(rnd, this.socket, address); + } + + public SocketTst(String address, int port, Random rnd) throws UnknownHostException, IOException { + this.socket = new Socket(address, port); + bagot = new Bagot(rnd, this.socket, InetAddress.getByName(address)); + } + + public SocketTst(String address, int port, InetAddress localAddr, int localPort, Random rnd) throws IOException { + this.socket = new Socket(address, port, localAddr, localPort); + bagot = new Bagot(rnd, this.socket, InetAddress.getByName(address)); + } + + public Socket getSocket() { + return this.socket; + } + + public void startBagot() { + bagot.start(); + } + }; + + private final Random rnd; + + public SocketTstFactory() { + super(); + LOG.info("Creating a new SocketTstFactory"); + this.rnd = new Random(); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + SocketTst sockTst; + sockTst = new SocketTst(host, port, this.rnd); + sockTst.startBagot(); + return sockTst.getSocket(); + } + + @Override + public Socket createSocket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException { + SocketTst sockTst; + sockTst = new SocketTst(host, port, localAddress, localPort, this.rnd); + sockTst.startBagot(); + return sockTst.getSocket(); + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + SocketTst sockTst; + sockTst = new SocketTst(host, port, this.rnd); + sockTst.startBagot(); + return sockTst.getSocket(); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException { + SocketTst sockTst; + sockTst = new SocketTst(host, port, localAddress, localPort, this.rnd); + sockTst.startBagot(); + return sockTst.getSocket(); + } + + private final static SocketTstFactory client = new SocketTstFactory(); + + public static SocketFactory getDefault() { + return client; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslBrokerServiceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslBrokerServiceTest.java new file mode 100644 index 0000000000..5c8d03af2a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslBrokerServiceTest.java @@ -0,0 +1,194 @@ +/** + * 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.transport.tcp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.security.KeyStore; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import junit.framework.Test; +import junit.textui.TestRunner; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.SslBrokerService; +import org.apache.activemq.broker.SslContext; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.transport.TransportBrokerTestSupport; +import org.apache.activemq.transport.TransportFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SslBrokerServiceTest extends TransportBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(SslBrokerServiceTest.class); + + TransportConnector needClientAuthConnector; + TransportConnector limitedCipherSuites; + + protected String getBindLocation() { + return "ssl://localhost:0"; + } + + @Override + protected BrokerService createBroker() throws Exception { + + // http://java.sun.com/javase/javaseforbusiness/docs/TLSReadme.html + // work around: javax.net.ssl.SSLHandshakeException: renegotiation is not allowed + System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true"); + + SslBrokerService service = new SslBrokerService(); + service.setPersistent(false); + + KeyManager[] km = getKeyManager(); + TrustManager[] tm = getTrustManager(); + connector = service.addSslConnector(getBindLocation(), km, tm, null); + limitedCipherSuites = service.addSslConnector("ssl://localhost:0?transport.enabledCipherSuites=SSL_RSA_WITH_RC4_128_SHA,SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", km, tm, null); + needClientAuthConnector = service.addSslConnector("ssl://localhost:0?transport.needClientAuth=true", km, tm, null); + + // for client side + SslTransportFactory sslFactory = new SslTransportFactory(); + SslContext ctx = new SslContext(km, tm, null); + SslContext.setCurrentSslContext(ctx); + TransportFactory.registerTransportFactory("ssl", sslFactory); + + return service; + } + + public void testNeedClientAuthReject() throws Exception { + SSLContext context = SSLContext.getInstance("TLS"); + // no client cert + context.init(null, getTrustManager(), null); + + try { + makeSSLConnection(context, null, needClientAuthConnector); + fail("expected failure on no client cert"); + } catch (SSLException expected) { + expected.printStackTrace(); + } + // should work with regular connector + makeSSLConnection(context, null, connector); + } + + public void testNeedClientAuthSucceed() throws Exception { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(getKeyManager(), getTrustManager(), null); + makeSSLConnection(context, null, needClientAuthConnector); + } + + public void testCipherSuitesDisabled() throws Exception { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(getKeyManager(), getTrustManager(), null); + + // Enable only one cipher suite which is not enabled on the server + try { + makeSSLConnection(context, new String[]{ "SSL_RSA_WITH_RC4_128_MD5" }, limitedCipherSuites); + fail("expected failure on non allowed cipher suite"); + } catch (SSLException expectedOnNotAnAvailableSuite) { + } + + // ok with the enabled one + makeSSLConnection(context, new String[]{ "SSL_RSA_WITH_RC4_128_SHA" }, limitedCipherSuites); + } + + private void makeSSLConnection(SSLContext context, String enabledSuites[], TransportConnector connector) throws Exception, + UnknownHostException, SocketException { + SSLSocket sslSocket = (SSLSocket) context.getSocketFactory().createSocket("localhost", connector.getUri().getPort()); + + if (enabledSuites != null) { + sslSocket.setEnabledCipherSuites(enabledSuites); + } + sslSocket.setSoTimeout(5000); + + SSLSession session = sslSocket.getSession(); + sslSocket.startHandshake(); + LOG.info("cyphersuite: " + session.getCipherSuite()); + LOG.info("peer port: " + session.getPeerPort()); + LOG.info("peer cert: " + session.getPeerCertificateChain()[0].toString()); + } + + public static TrustManager[] getTrustManager() throws Exception { + TrustManager[] trustStoreManagers = null; + KeyStore trustedCertStore = KeyStore.getInstance(SslTransportBrokerTest.KEYSTORE_TYPE); + + trustedCertStore.load(new FileInputStream(SslTransportBrokerTest.TRUST_KEYSTORE), null); + TrustManagerFactory tmf = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + + tmf.init(trustedCertStore); + trustStoreManagers = tmf.getTrustManagers(); + return trustStoreManagers; + } + + public static KeyManager[] getKeyManager() throws Exception { + KeyManagerFactory kmf = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + KeyStore ks = KeyStore.getInstance(SslTransportBrokerTest.KEYSTORE_TYPE); + KeyManager[] keystoreManagers = null; + + byte[] sslCert = loadClientCredential(SslTransportBrokerTest.SERVER_KEYSTORE); + + + if (sslCert != null && sslCert.length > 0) { + ByteArrayInputStream bin = new ByteArrayInputStream(sslCert); + ks.load(bin, SslTransportBrokerTest.PASSWORD.toCharArray()); + kmf.init(ks, SslTransportBrokerTest.PASSWORD.toCharArray()); + keystoreManagers = kmf.getKeyManagers(); + } + return keystoreManagers; + } + + private static byte[] loadClientCredential(String fileName) throws IOException { + if (fileName == null) { + return null; + } + FileInputStream in = new FileInputStream(fileName); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buf = new byte[512]; + int i = in.read(buf); + while (i > 0) { + out.write(buf, 0, i); + i = in.read(buf); + } + in.close(); + return out.toByteArray(); + } + + protected void setUp() throws Exception { + maxWait = 10000; + super.setUp(); + } + + public static Test suite() { + return suite(SslBrokerServiceTest.class); + } + + public static void main(String[] args) { + TestRunner.run(suite()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslContextBrokerServiceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslContextBrokerServiceTest.java new file mode 100644 index 0000000000..4d44c461e2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslContextBrokerServiceTest.java @@ -0,0 +1,66 @@ +/** + * 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.transport.tcp; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * + */ +public class SslContextBrokerServiceTest extends TestCase { + + private ClassPathXmlApplicationContext context; + private BrokerService broker; + private TransportConnector connector; + + public void testConfiguration() throws URISyntaxException { + + assertNotNull(broker); + assertNotNull(connector); + + assertEquals(new URI("ssl://localhost:61616"), connector.getUri()); + + assertNotNull(broker.getSslContext()); + assertFalse(broker.getSslContext().getKeyManagers().isEmpty()); + assertFalse(broker.getSslContext().getTrustManagers().isEmpty()); + + } + + @Override + protected void setUp() throws Exception { + Thread.currentThread().setContextClassLoader(SslContextBrokerServiceTest.class.getClassLoader()); + context = new ClassPathXmlApplicationContext("org/apache/activemq/transport/tcp/activemq-ssl.xml"); + Map beansOfType = context.getBeansOfType(BrokerService.class); + broker = beansOfType.values().iterator().next(); + connector = broker.getTransportConnectors().get(0); + } + + @Override + protected void tearDown() throws Exception { + + context.destroy(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslContextNBrokerServiceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslContextNBrokerServiceTest.java new file mode 100644 index 0000000000..03a1d84148 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslContextNBrokerServiceTest.java @@ -0,0 +1,147 @@ +/** + * 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.transport.tcp; + +import java.net.URI; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Iterator; +import java.util.Map; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import static org.junit.Assert.*; + +public class SslContextNBrokerServiceTest { + private static final transient Logger LOG = LoggerFactory.getLogger(SslContextNBrokerServiceTest.class); + + private ClassPathXmlApplicationContext context; + Map beansOfType; + + @Test(timeout = 3 * 60 * 1000) + public void testDummyConfigurationIsolation() throws Exception { + assertTrue("dummy bean has dummy cert", verifyCredentials("dummy")); + } + + @Test(timeout = 3 * 60 * 1000) + public void testActiveMQDotOrgConfigurationIsolation() throws Exception { + assertTrue("good bean has amq cert", verifyCredentials("activemq.org")); + } + + private boolean verifyCredentials(String name) throws Exception { + boolean result = false; + BrokerService broker = getBroker(name); + assertNotNull(name, broker); + broker.start(); + broker.waitUntilStarted(); + try { + result = verifySslCredentials(broker); + } finally { + broker.stop(); + } + return result; + } + + private boolean verifySslCredentials(BrokerService broker) throws Exception { + TransportConnector connector = broker.getTransportConnectors().get(0); + URI brokerUri = connector.getConnectUri(); + + SSLContext context = SSLContext.getInstance("TLS"); + CertChainCatcher catcher = new CertChainCatcher(); + context.init(null, new TrustManager[] { catcher }, null); + + SSLSocketFactory factory = context.getSocketFactory(); + LOG.info("Connecting to broker: " + broker.getBrokerName() + " on: " + brokerUri.getHost() + ":" + brokerUri.getPort()); + SSLSocket socket = (SSLSocket) factory.createSocket(brokerUri.getHost(), brokerUri.getPort()); + socket.setSoTimeout(2 * 60 * 1000); + socket.startHandshake(); + socket.close(); + + boolean matches = false; + if (catcher.serverCerts != null) { + for (int i = 0; i < catcher.serverCerts.length; i++) { + X509Certificate cert = catcher.serverCerts[i]; + LOG.info(" " + (i + 1) + " Issuer " + cert.getIssuerDN()); + } + if (catcher.serverCerts.length > 0) { + String issuer = catcher.serverCerts[0].getIssuerDN().toString(); + if (issuer.indexOf(broker.getBrokerName()) != -1) { + matches = true; + } + } + } + return matches; + } + + private BrokerService getBroker(String name) { + BrokerService result = null; + Iterator iterator = beansOfType.values().iterator(); + while (iterator.hasNext()) { + BrokerService candidate = iterator.next(); + if (candidate.getBrokerName().equals(name)) { + result = candidate; + break; + } + } + return result; + } + + @Before + public void setUp() throws Exception { + // System.setProperty("javax.net.debug", "ssl"); + Thread.currentThread().setContextClassLoader(SslContextNBrokerServiceTest.class.getClassLoader()); + context = new ClassPathXmlApplicationContext("org/apache/activemq/transport/tcp/n-brokers-ssl.xml"); + beansOfType = context.getBeansOfType(BrokerService.class); + } + + @After + public void tearDown() throws Exception { + context.destroy(); + } + + class CertChainCatcher implements X509TrustManager { + X509Certificate[] serverCerts; + + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + serverCerts = arg0; + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslSocketHelper.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslSocketHelper.java new file mode 100644 index 0000000000..52a5db1eda --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslSocketHelper.java @@ -0,0 +1,44 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.security.cert.X509Certificate; + +import javax.management.remote.JMXPrincipal; +import javax.net.ssl.SSLSocket; + +/** + * + */ +public final class SslSocketHelper { + + private SslSocketHelper() { + } + + public static SSLSocket createSSLSocket(String certDistinguishedName, boolean wantAuth, boolean needAuth) + throws IOException { + JMXPrincipal principal = new JMXPrincipal(certDistinguishedName); + X509Certificate cert = new StubX509Certificate(principal); + StubSSLSession sslSession = new StubSSLSession(cert); + + StubSSLSocket sslSocket = new StubSSLSocket(sslSession); + sslSocket.setWantClientAuth(wantAuth); + sslSocket.setNeedClientAuth(needAuth); + return sslSocket; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportBrokerTest.java new file mode 100644 index 0000000000..de07a74f86 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportBrokerTest.java @@ -0,0 +1,62 @@ +/** + * 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.transport.tcp; + +import java.net.URI; +import java.net.URISyntaxException; +import junit.framework.Test; +import junit.textui.TestRunner; +import org.apache.activemq.transport.TransportBrokerTestSupport; + +public class SslTransportBrokerTest extends TransportBrokerTestSupport { + + public static final String KEYSTORE_TYPE = "jks"; + public static final String PASSWORD = "password"; + public static final String SERVER_KEYSTORE = "src/test/resources/server.keystore"; + public static final String TRUST_KEYSTORE = "src/test/resources/client.keystore"; + + protected String getBindLocation() { + return "ssl://localhost:0?transport.soWriteTimeout=20000"; + } + + @Override + protected URI getBindURI() throws URISyntaxException { + return new URI("ssl://localhost:0?soWriteTimeout=20000"); + } + + protected void setUp() throws Exception { + System.setProperty("javax.net.ssl.trustStore", TRUST_KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE); + System.setProperty("javax.net.ssl.keyStore", SERVER_KEYSTORE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE); + //System.setProperty("javax.net.debug", "ssl,handshake,data,trustmanager"); + + maxWait = 10000; + super.setUp(); + } + + public static Test suite() { + return suite(SslTransportBrokerTest.class); + } + + public static void main(String[] args) { + TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportFactoryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportFactoryTest.java new file mode 100644 index 0000000000..af9d6725ba --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportFactoryTest.java @@ -0,0 +1,147 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; +import org.apache.activemq.openwire.OpenWireFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SslTransportFactoryTest extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(SslTransportFactoryTest.class); + + private SslTransportFactory factory; + private boolean verbose; + + protected void setUp() throws Exception { + factory = new SslTransportFactory(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testBindServerOptions() throws IOException { + + SslTransportServer sslTransportServer = null; + + for (int i = 0; i < 4; ++i) { + final boolean wantClientAuth = (i & 0x1) == 1; + final boolean needClientAuth = (i & 0x2) == 1; + + String options = "wantClientAuth=" + (wantClientAuth ? "true" : "false") + "&needClientAuth=" + + (needClientAuth ? "true" : "false"); + + try { + sslTransportServer = (SslTransportServer)factory.doBind(new URI( + "ssl://localhost:61616?" + + options)); + } catch (Exception e) { + fail("Unable to bind to address: " + e.getMessage()); + } + + assertEquals("Created ServerSocket did not have correct wantClientAuth status.", + sslTransportServer.getWantClientAuth(), wantClientAuth); + + assertEquals("Created ServerSocket did not have correct needClientAuth status.", + sslTransportServer.getNeedClientAuth(), needClientAuth); + + try { + sslTransportServer.stop(); + } catch (Exception e) { + fail("Unable to stop TransportServer: " + e.getMessage()); + } + } + } + + private int getMthNaryDigit(int number, int digitIdx, int numBase) { + return (number / ((int)Math.pow(numBase, digitIdx))) % numBase; + } + + public void testCompositeConfigure() throws IOException { + // The 5 options being tested. + int optionSettings[] = new int[5]; + + String optionNames[] = {"wantClientAuth", "needClientAuth", "socket.wantClientAuth", + "socket.needClientAuth", "socket.useClientMode"}; + + // Using a trinary interpretation of i to set all possible values of + // stub options for socket and transport. + // 2 transport options, 3 socket options, 3 settings for each option => + // 3^5 = 243 combos. + for (int i = 0; i < 243; ++i) { + Map options = new HashMap(); + + for (int j = 0; j < 5; ++j) { + // -1 since the option range is [-1,1], not [0,2]. + optionSettings[j] = getMthNaryDigit(i, j, 3) - 1; + + if (optionSettings[j] != -1) { + options.put(optionNames[j], optionSettings[j] == 1 ? "true" : "false"); + } + } + + StubSSLSocket socketStub = new StubSSLSocket(null); + StubSslTransport transport = null; + + try { + transport = new StubSslTransport(null, socketStub); + } catch (Exception e) { + fail("Unable to create StubSslTransport: " + e.getMessage()); + } + + if (verbose) { + LOG.info(""); + LOG.info("Iteration: " + i); + LOG.info("Map settings: " + options); + for (int x = 0; x < optionSettings.length; x++) { + LOG.info("optionSetting[" + x + "] = " + optionSettings[x]); + } + } + + factory.compositeConfigure(transport, new OpenWireFormat(), options); + + // lets start the transport to force the introspection + try { + transport.start(); + } catch (Exception e) { + // ignore bad connection + } + + if (socketStub.getWantClientAuthStatus() != optionSettings[2]) { + LOG.info("sheiite"); + } + + assertEquals("wantClientAuth was not properly set for iteration: " + i, optionSettings[0], + transport.getWantClientAuthStatus()); + assertEquals("needClientAuth was not properly set for iteration: " + i, optionSettings[1], + transport.getNeedClientAuthStatus()); + assertEquals("socket.wantClientAuth was not properly set for iteration: " + i, optionSettings[2], + socketStub.getWantClientAuthStatus()); + assertEquals("socket.needClientAuth was not properly set for iteration: " + i, optionSettings[3], + socketStub.getNeedClientAuthStatus()); + assertEquals("socket.useClientMode was not properly set for iteration: " + i, optionSettings[4], + socketStub.getUseClientModeStatus()); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportServerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportServerTest.java new file mode 100644 index 0000000000..4053a5bf07 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportServerTest.java @@ -0,0 +1,92 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.URI; + +import junit.framework.TestCase; + +public class SslTransportServerTest extends TestCase { + private SslTransportServer sslTransportServer; + private StubSSLServerSocket sslServerSocket; + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + private void createAndBindTransportServer(boolean wantClientAuth, boolean needClientAuth, String options) throws IOException { + sslServerSocket = new StubSSLServerSocket(); + + StubSSLSocketFactory socketFactory = new StubSSLSocketFactory(sslServerSocket); + + try { + sslTransportServer = new SslTransportServer(null, new URI("ssl://localhost:61616?" + options), socketFactory); + } catch (Exception e) { + fail("Unable to create SslTransportServer."); + } + + sslTransportServer.setWantClientAuth(wantClientAuth); + sslTransportServer.setNeedClientAuth(needClientAuth); + + sslTransportServer.bind(); + } + + public void testWantAndNeedClientAuthSetters() throws IOException { + for (int i = 0; i < 4; ++i) { + String options = ""; + singleTest(i, options); + } + } + + public void testWantAndNeedAuthReflection() throws IOException { + for (int i = 0; i < 4; ++i) { + String options = "wantClientAuth=" + (getWantClientAuth(i) ? "true" : "false") + + "&needClientAuth=" + (getNeedClientAuth(i) ? "true" : "false"); + singleTest(i, options); + } + } + + private void singleTest(int i, String options) throws IOException { + final boolean wantClientAuth = getWantClientAuth(i); + final boolean needClientAuth = getNeedClientAuth(i); + + final int expectedWantStatus = (needClientAuth? StubSSLServerSocket.UNTOUCHED: wantClientAuth ? StubSSLServerSocket.TRUE : StubSSLServerSocket.UNTOUCHED); + final int expectedNeedStatus = (needClientAuth ? StubSSLServerSocket.TRUE : StubSSLServerSocket.UNTOUCHED ); + + + createAndBindTransportServer(wantClientAuth, needClientAuth, options); + + assertEquals("Created ServerSocket did not have correct wantClientAuth status. wantClientAuth: " + wantClientAuth + ", needClientAuth: " + needClientAuth, + expectedWantStatus, sslServerSocket.getWantClientAuthStatus()); + + assertEquals("Created ServerSocket did not have correct needClientAuth status. wantClientAuth: " + wantClientAuth + ", needClientAuth: " + needClientAuth, + expectedNeedStatus, sslServerSocket.getNeedClientAuthStatus()); + } + + private boolean getNeedClientAuth(int i) { + return ((i & 0x2) == 0x2); + } + + private boolean getWantClientAuth(int i) { + return ((i & 0x1) == 0x1); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportTest.java new file mode 100644 index 0000000000..d049745450 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/SslTransportTest.java @@ -0,0 +1,96 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.security.cert.X509Certificate; + +import javax.management.remote.JMXPrincipal; +import javax.net.ssl.SSLSocket; + +import junit.framework.TestCase; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.transport.StubTransportListener; +import org.apache.activemq.wireformat.ObjectStreamWireFormat; + +/** + * Unit tests for the SslTransport class. + */ +public class SslTransportTest extends TestCase { + + SSLSocket sslSocket; + StubTransportListener stubListener; + + String username; + String password; + String certDistinguishedName; + + protected void setUp() throws Exception { + certDistinguishedName = "ThisNameIsDistinguished"; + username = "SomeUserName"; + password = "SomePassword"; + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + private void createTransportAndConsume(boolean wantAuth, boolean needAuth) throws IOException { + JMXPrincipal principal = new JMXPrincipal(certDistinguishedName); + X509Certificate cert = new StubX509Certificate(principal); + StubSSLSession sslSession = new StubSSLSession(cert); + + sslSocket = new StubSSLSocket(sslSession); + sslSocket.setWantClientAuth(wantAuth); + sslSocket.setNeedClientAuth(needAuth); + + SslTransport transport = new SslTransport(new ObjectStreamWireFormat(), sslSocket); + + stubListener = new StubTransportListener(); + + transport.setTransportListener(stubListener); + + ConnectionInfo sentInfo = new ConnectionInfo(); + + sentInfo.setUserName(username); + sentInfo.setPassword(password); + + transport.doConsume(sentInfo); + } + + public void testKeepClientUserName() throws IOException { + createTransportAndConsume(true, true); + + final ConnectionInfo receivedInfo = (ConnectionInfo)stubListener.getCommands().remove(); + + X509Certificate receivedCert; + + try { + receivedCert = ((X509Certificate[])receivedInfo.getTransportContext())[0]; + } catch (Exception e) { + receivedCert = null; + } + + if (receivedCert == null) { + fail("Transmitted certificate chain was not attached to ConnectionInfo."); + } + + assertEquals("Received certificate distinguished name did not match the one transmitted.", certDistinguishedName, receivedCert.getSubjectDN().getName()); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLServerSocket.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLServerSocket.java new file mode 100644 index 0000000000..cc3d91cd16 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLServerSocket.java @@ -0,0 +1,97 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; + +import javax.net.ssl.SSLServerSocket; + +public class StubSSLServerSocket extends SSLServerSocket { + public static final int UNTOUCHED = -1; + public static final int FALSE = 0; + public static final int TRUE = 1; + + private int wantClientAuthStatus = UNTOUCHED; + private int needClientAuthStatus = UNTOUCHED; + + public StubSSLServerSocket() throws IOException { + + } + + public int getWantClientAuthStatus() { + return wantClientAuthStatus; + } + + public int getNeedClientAuthStatus() { + return needClientAuthStatus; + } + + public void setWantClientAuth(boolean want) { + wantClientAuthStatus = want ? TRUE : FALSE; + } + + public void setNeedClientAuth(boolean need) { + needClientAuthStatus = need ? TRUE : FALSE; + } + + // --- Stubbed methods --- + + public boolean getEnableSessionCreation() { + return false; + } + + public String[] getEnabledCipherSuites() { + return null; + } + + public String[] getEnabledProtocols() { + return null; + } + + public boolean getNeedClientAuth() { + return false; + } + + public String[] getSupportedCipherSuites() { + return null; + } + + public String[] getSupportedProtocols() { + return null; + } + + public boolean getUseClientMode() { + return false; + } + + public boolean getWantClientAuth() { + return false; + } + + public void setEnableSessionCreation(boolean flag) { + } + + public void setEnabledCipherSuites(String[] suites) { + } + + public void setEnabledProtocols(String[] protocols) { + } + + public void setUseClientMode(boolean mode) { + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSession.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSession.java new file mode 100644 index 0000000000..7c0a70b071 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSession.java @@ -0,0 +1,133 @@ +/** + * 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.transport.tcp; + +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; + +class StubSSLSession implements SSLSession { + + X509Certificate cert; + boolean isVerified; + + public StubSSLSession(X509Certificate cert) { + if (cert != null) { + this.isVerified = true; + this.cert = cert; + } else { + this.isVerified = false; + this.cert = null; + } + } + + public void setIsVerified(boolean verified) { + this.isVerified = verified; + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { + if (this.isVerified) { + return new X509Certificate[] {this.cert}; + } else { + throw new SSLPeerUnverifiedException("Socket is unverified."); + } + } + + // --- Stubbed methods --- + + public byte[] getId() { + return null; + } + + public SSLSessionContext getSessionContext() { + return null; + } + + public long getCreationTime() { + return 0; + } + + public long getLastAccessedTime() { + return 0; + } + + public void invalidate() { + } + + public boolean isValid() { + return false; + } + + public void putValue(String arg0, Object arg1) { + } + + public Object getValue(String arg0) { + return null; + } + + public void removeValue(String arg0) { + } + + public String[] getValueNames() { + return null; + } + + public Certificate[] getLocalCertificates() { + return null; + } + + public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { + return null; + } + + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { + return null; + } + + public Principal getLocalPrincipal() { + return null; + } + + public String getCipherSuite() { + return null; + } + + public String getProtocol() { + return null; + } + + public String getPeerHost() { + return null; + } + + public int getPeerPort() { + return 0; + } + + public int getPacketBufferSize() { + return 0; + } + + public int getApplicationBufferSize() { + return 0; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSocket.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSocket.java new file mode 100644 index 0000000000..d1de9aaef5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSocket.java @@ -0,0 +1,124 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; + +public class StubSSLSocket extends SSLSocket { + + public static final int UNTOUCHED = -1; + public static final int FALSE = 0; + public static final int TRUE = 1; + + private int wantClientAuthStatus = UNTOUCHED; + private int needClientAuthStatus = UNTOUCHED; + private int useClientModeStatus = UNTOUCHED; + private final StubSSLSession session; + + public StubSSLSocket(StubSSLSession ses) { + this.session = ses; + } + + public void setWantClientAuth(boolean arg0) { + this.wantClientAuthStatus = arg0 ? TRUE : FALSE; + } + + public void setNeedClientAuth(boolean arg0) { + this.needClientAuthStatus = arg0 ? TRUE : FALSE; + if (session != null) { + this.session.setIsVerified(arg0); + } + } + + public void setUseClientMode(boolean arg0) { + useClientModeStatus = arg0 ? TRUE : FALSE; + } + + public boolean getWantClientAuth() { + return wantClientAuthStatus == TRUE; + } + + public boolean getNeedClientAuth() { + return needClientAuthStatus == TRUE; + } + + public boolean getUseClientMode() { + return useClientModeStatus == TRUE; + } + + public int getWantClientAuthStatus() { + return wantClientAuthStatus; + } + + public int getNeedClientAuthStatus() { + return needClientAuthStatus; + } + + public int getUseClientModeStatus() { + return useClientModeStatus; + } + + public SSLSession getSession() { + return this.session; + } + + // --- Stubbed methods --- + + public String[] getSupportedCipherSuites() { + return null; + } + + public String[] getEnabledCipherSuites() { + return null; + } + + public void setEnabledCipherSuites(String[] arg0) { + } + + public String[] getSupportedProtocols() { + return null; + } + + public String[] getEnabledProtocols() { + return null; + } + + public void setEnabledProtocols(String[] arg0) { + } + + public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) { + } + + public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) { + } + + public void startHandshake() throws IOException { + } + + public void setEnableSessionCreation(boolean arg0) { + } + + public boolean getEnableSessionCreation() { + return false; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSocketFactory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSocketFactory.java new file mode 100644 index 0000000000..fa13cc30ff --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSSLSocketFactory.java @@ -0,0 +1,55 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; + +import javax.net.ssl.SSLServerSocketFactory; + +public class StubSSLSocketFactory extends SSLServerSocketFactory { + + private final ServerSocket retServerSocket; + + public StubSSLSocketFactory(ServerSocket returnServerSocket) { + retServerSocket = returnServerSocket; + } + + public ServerSocket createServerSocket(int arg0) throws IOException { + return retServerSocket; + } + + public ServerSocket createServerSocket(int arg0, int arg1) throws IOException { + return retServerSocket; + } + + public ServerSocket createServerSocket(int arg0, int arg1, InetAddress arg2) throws IOException { + return retServerSocket; + } + + // --- Stubbed Methods --- + + public String[] getDefaultCipherSuites() { + return null; + } + + public String[] getSupportedCipherSuites() { + return null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSslTransport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSslTransport.java new file mode 100644 index 0000000000..f5d2dc7eef --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubSslTransport.java @@ -0,0 +1,51 @@ +/** + * 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.transport.tcp; + +import javax.net.ssl.SSLSocket; + +import org.apache.activemq.wireformat.WireFormat; + +public class StubSslTransport extends SslTransport { + public static final int UNTOUCHED = -1; + public static final int FALSE = 0; + public static final int TRUE = 1; + + private int wantClientAuthStatus = UNTOUCHED; + private int needClientAuthStatus = UNTOUCHED; + + public StubSslTransport(WireFormat wireFormat, SSLSocket socket) throws Exception { + super(wireFormat, socket); + } + + public void setWantClientAuth(boolean arg0) { + this.wantClientAuthStatus = arg0 ? TRUE : FALSE; + } + + public void setNeedClientAuth(boolean arg0) { + this.needClientAuthStatus = arg0 ? TRUE : FALSE; + } + + public int getWantClientAuthStatus() { + return wantClientAuthStatus; + } + + public int getNeedClientAuthStatus() { + return needClientAuthStatus; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubX509Certificate.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubX509Certificate.java new file mode 100644 index 0000000000..3cd873ad7d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/StubX509Certificate.java @@ -0,0 +1,138 @@ +/** + * 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.transport.tcp; + +import java.math.BigInteger; +import java.security.Principal; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Set; + +public class StubX509Certificate extends X509Certificate { + + private final Principal id; + + public StubX509Certificate(Principal id) { + this.id = id; + } + + public Principal getSubjectDN() { + return this.id; + } + + // --- Stubbed Methods --- + public void checkValidity() { + } + + public void checkValidity(Date arg0) { + } + + public int getVersion() { + return 0; + } + + public BigInteger getSerialNumber() { + return null; + } + + public Principal getIssuerDN() { + return null; + } + + public Date getNotBefore() { + return null; + } + + public Date getNotAfter() { + return null; + } + + public byte[] getTBSCertificate() { + return null; + } + + public byte[] getSignature() { + return null; + } + + public String getSigAlgName() { + return null; + } + + public String getSigAlgOID() { + return null; + } + + public byte[] getSigAlgParams() { + return null; + } + + public boolean[] getIssuerUniqueID() { + return null; + } + + public boolean[] getSubjectUniqueID() { + return null; + } + + public boolean[] getKeyUsage() { + return null; + } + + public int getBasicConstraints() { + return 0; + } + + public byte[] getEncoded() { + return null; + } + + public void verify(PublicKey arg0) { + } + + public void verify(PublicKey arg0, String arg1) { + } + + public String toString() { + return null; + } + + public PublicKey getPublicKey() { + return null; + } + + public boolean hasUnsupportedCriticalExtension() { + return false; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Set getCriticalExtensionOIDs() { + return null; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Set getNonCriticalExtensionOIDs() { + return null; + } + + public byte[] getExtensionValue(String arg0) { + return null; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransport.java new file mode 100644 index 0000000000..176934fae5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransport.java @@ -0,0 +1,49 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.URI; +import java.net.UnknownHostException; + +import org.apache.activemq.Service; +import org.apache.activemq.transport.Transport; + +import org.apache.activemq.wireformat.WireFormat; + +import javax.net.SocketFactory; + +/** + * An implementation of the {@link Transport} interface using raw tcp/ip + * + * @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com (logging improvement modifications) + * + */ +public class TcpFaultyTransport extends TcpTransport implements Transport, Service, Runnable { + + public TcpFaultyTransport(WireFormat wireFormat, SocketFactory socketFactory, URI remoteLocation, + URI localLocation) throws UnknownHostException, IOException { + super(wireFormat, socketFactory, remoteLocation, localLocation); + } + + /** + * @return pretty print of 'this' + */ + public String toString() { + return "tcpfaulty://" + socket.getInetAddress() + ":" + socket.getPort(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransportFactory.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransportFactory.java new file mode 100644 index 0000000000..592f2fb6f5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransportFactory.java @@ -0,0 +1,97 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; + +import javax.net.ServerSocketFactory; +import javax.net.SocketFactory; + +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportServer; +import org.apache.activemq.util.IOExceptionSupport; +import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.URISupport; +import org.apache.activemq.wireformat.WireFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Automatically generated socket.close() calls to simulate network faults + */ +public class TcpFaultyTransportFactory extends TcpTransportFactory { + private static final Logger LOG = LoggerFactory.getLogger(TcpFaultyTransportFactory.class); + + protected TcpFaultyTransport createTcpFaultyTransport(WireFormat wf, SocketFactory socketFactory, URI location, URI localLocation) throws UnknownHostException, IOException { + return new TcpFaultyTransport(wf, socketFactory, location, localLocation); + } + + protected Transport createTransport(URI location, WireFormat wf) throws UnknownHostException, IOException { + URI localLocation = null; + String path = location.getPath(); + // see if the path is a local URI location + if (path != null && path.length() > 0) { + int localPortIndex = path.indexOf(':'); + try { + Integer.parseInt(path.substring(localPortIndex + 1, path.length())); + String localString = location.getScheme() + ":/" + path; + localLocation = new URI(localString); + } catch (Exception e) { + LOG.warn("path isn't a valid local location for TcpTransport to use", e); + } + } + SocketFactory socketFactory = createSocketFactory(); + return createTcpFaultyTransport(wf, socketFactory, location, localLocation); + } + + protected TcpFaultyTransportServer createTcpFaultyTransportServer(final URI location, ServerSocketFactory serverSocketFactory) throws IOException, URISyntaxException { + return new TcpFaultyTransportServer(this, location, serverSocketFactory); + } + + public TransportServer doBind(final URI location) throws IOException { + try { + Map options = new HashMap(URISupport.parseParameters(location)); + + ServerSocketFactory serverSocketFactory = createServerSocketFactory(); + TcpFaultyTransportServer server = createTcpFaultyTransportServer(location, serverSocketFactory); + server.setWireFormatFactory(createWireFormatFactory(options)); + IntrospectionSupport.setProperties(server, options); + Map transportOptions = IntrospectionSupport.extractProperties(options, "transport."); + server.setTransportOption(transportOptions); + server.bind(); + + return server; + } catch (URISyntaxException e) { + throw IOExceptionSupport.create(e); + } + } + + + protected SocketFactory createSocketFactory() throws IOException { + return SocketTstFactory.getDefault(); + } + + + protected ServerSocketFactory createServerSocketFactory() throws IOException { + return ServerSocketTstFactory.getDefault(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransportServer.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransportServer.java new file mode 100644 index 0000000000..36c0fd54d2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpFaultyTransportServer.java @@ -0,0 +1,46 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.activemq.util.ServiceListener; + +import javax.net.ServerSocketFactory; + +/** + * A TCP based implementation of {@link TransportServer} + * + * @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com (logging improvement modifications) + * + */ + +public class TcpFaultyTransportServer extends TcpTransportServer implements ServiceListener{ + + public TcpFaultyTransportServer(TcpFaultyTransportFactory transportFactory, URI location, ServerSocketFactory serverSocketFactory) throws IOException, URISyntaxException { + super(transportFactory, location, serverSocketFactory); + } + + /** + * @return pretty print of this + */ + public String toString() { + return "" + getBindLocation(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportBindTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportBindTest.java new file mode 100644 index 0000000000..61c20aea9c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportBindTest.java @@ -0,0 +1,73 @@ +/** + * 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.transport.tcp; + +import java.util.Timer; +import java.util.TimerTask; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; + +public class TcpTransportBindTest extends EmbeddedBrokerTestSupport { + String addr = "tcp://localhost:0"; + + /** + * exercise some server side socket options + * @throws Exception + */ + @Override + protected void setUp() throws Exception { + bindAddress = addr + "?transport.reuseAddress=true&transport.soTimeout=1000"; + super.setUp(); + + addr = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + public void testConnect() throws Exception { + Connection connection = new ActiveMQConnectionFactory(addr).createConnection(); + connection.start(); + } + + public void testReceiveThrowsException() throws Exception { + Connection connection = new ActiveMQConnectionFactory(addr).createConnection(); + connection.start(); + Session sess = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = sess.createConsumer(createDestination()); + class StopTask extends TimerTask { + @Override + public void run() { + try { + broker.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + Timer timer = new Timer(); + timer.schedule(new StopTask(), 1000); + try { + consumer.receive(30000); + fail("Should have thrown an exception"); + } catch (Exception e) { + // should fail + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportBrokerTest.java new file mode 100644 index 0000000000..9ce2e8bbcb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportBrokerTest.java @@ -0,0 +1,41 @@ +/** + * 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.transport.tcp; + +import junit.framework.Test; +import org.apache.activemq.transport.TransportBrokerTestSupport; + +public class TcpTransportBrokerTest extends TransportBrokerTestSupport { + + protected String getBindLocation() { + return "tcp://localhost:0"; + } + + protected void setUp() throws Exception { + maxWait = 2000; + super.setUp(); + } + + public static Test suite() { + return suite(TcpTransportBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportServerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportServerTest.java new file mode 100644 index 0000000000..46db53f15f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TcpTransportServerTest.java @@ -0,0 +1,79 @@ +/** + * 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.transport.tcp; + +import junit.framework.TestCase; +import org.apache.activemq.transport.*; + +import java.net.Socket; +import java.net.URI; +import java.util.HashMap; + +/** + * @author Christian Posta + */ +public class TcpTransportServerTest extends TestCase{ + + public void testDefaultPropertiesSetOnTransport() throws Exception { + TcpTransportServer server = (TcpTransportServer) TransportFactory.bind(new URI("tcp://localhost:61616?trace=true")); + server.setTransportOption(new HashMap()); + + server.setAcceptListener(new TransportAcceptListener() { + @Override + public void onAccept(Transport transport) { + assertTrue("This transport does not have a TransportLogger!!", hasTransportLogger(transport)); + } + + @Override + public void onAcceptError(Exception error) { + fail("Should not have received an error!"); + } + }); + + server.start(); + + + Socket socket = new Socket("localhost", 61616); + server.handleSocket(socket); + server.stop(); + + + } + + private boolean hasTransportLogger(Transport transport) { + boolean end = false; + + Transport current = transport; + while(!end) { + + if (current instanceof TransportFilter) { + TransportFilter filter = (TransportFilter) current; + + if(filter instanceof TransportLogger){ + return true; + } + + current = filter.getNext(); + } + else { + end = true; + } + } + + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TransportConnectorInvalidSocketOptionsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TransportConnectorInvalidSocketOptionsTest.java new file mode 100644 index 0000000000..5a171b713d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TransportConnectorInvalidSocketOptionsTest.java @@ -0,0 +1,65 @@ +/** + * 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.transport.tcp; + +import javax.jms.JMSException; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.junit.Test; + +public class TransportConnectorInvalidSocketOptionsTest extends TestCase { + + @Test + public void testClientParameters() throws Exception { + try { + new ActiveMQConnectionFactory("tcp://localhost:42?foo=bar").createConnection(); + fail("Should have thrown an exception"); + } catch (Exception e) { + assertEquals(JMSException.class, e.getClass()); + assertEquals(IllegalArgumentException.class, e.getCause().getClass()); + assertEquals("Invalid connect parameters: {foo=bar}", e.getCause().getMessage()); + } + } + + @Test + public void testClientSocketParameters() throws Exception { + BrokerService broker = null; + + try { + broker = new BrokerService(); + broker.setPersistent(false); + broker.addConnector("tcp://localhost:61616"); + broker.start(); + + try { + new ActiveMQConnectionFactory("tcp://localhost:61616?socket.foo=bar").createConnection(); + fail("Should have thrown an exception"); + } catch (Exception e) { + assertEquals(JMSException.class, e.getClass()); + assertEquals(IllegalArgumentException.class, e.getCause().getClass()); + assertEquals("Invalid socket parameters: {foo=bar}", e.getCause().getMessage()); + } + } finally { + if (broker != null) { + broker.stop(); + } + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TransportUriTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TransportUriTest.java new file mode 100644 index 0000000000..349c5c3fca --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/TransportUriTest.java @@ -0,0 +1,204 @@ +/** + * 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.transport.tcp; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TransportUriTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(TransportUriTest.class); + private static final String DIFF_SERV = "&diffServ="; + private static final String TOS = "&typeOfService="; + + protected Connection connection; + + public String prefix; + public String postfix; + + public void initCombosForTestUriOptionsWork() { + initSharedCombos(); + } + + public void testUriOptionsWork() throws Exception { + String uri = prefix + bindAddress + postfix; + LOG.info("Connecting via: " + uri); + + connection = new ActiveMQConnectionFactory(uri).createConnection(); + connection.start(); + } + + public void initCombosForTestValidDiffServOptionsWork() { + initSharedCombos(); + } + + public void testValidDiffServOptionsWork() throws Exception { + String[] validIntegerOptions = {"0", "1", "32", "62", "63"}; + for (String opt : validIntegerOptions) { + testValidOptionsWork(DIFF_SERV + opt, ""); + } + String[] validNameOptions = { "CS0", "CS1", "CS2", "CS3", "CS4", "CS5", "CS6", + "CS7", "EF", "AF11", "AF12","AF13", "AF21", "AF22", "AF23", "AF31", + "AF32", "AF33", "AF41", "AF42", "AF43" }; + for (String opt : validNameOptions) { + testValidOptionsWork(DIFF_SERV + opt, ""); + } + } + + public void initCombosForTestInvalidDiffServOptionDoesNotWork() { + initSharedCombos(); + } + + public void testInvalidDiffServOptionsDoesNotWork() throws Exception { + String[] invalidIntegerOptions = {"-2", "-1", "64", "65", "100", "255"}; + for (String opt : invalidIntegerOptions) { + testInvalidOptionsDoNotWork(DIFF_SERV + opt, ""); + } + String[] invalidNameOptions = {"hi", "", "A", "AF", "-AF21"}; + for (String opt : invalidNameOptions) { + testInvalidOptionsDoNotWork(DIFF_SERV + opt, ""); + } + } + + public void initCombosForTestValidTypeOfServiceOptionsWork() { + initSharedCombos(); + } + + public void testValidTypeOfServiceOptionsWork() throws Exception { + int[] validOptions = {0, 1, 32, 100, 254, 255}; + for (int opt : validOptions) { + testValidOptionsWork(TOS + opt, ""); + } + } + + public void initCombosForTestInvalidTypeOfServiceOptionDoesNotWork() { + initSharedCombos(); + } + + public void testInvalidTypeOfServiceOptionDoesNotWork() throws Exception { + int[] invalidOptions = {-2, -1, 256, 257}; + for (int opt : invalidOptions) { + testInvalidOptionsDoNotWork(TOS + opt, ""); + } + } + + public void initCombosForTestDiffServAndTypeOfServiceMutuallyExclusive() { + initSharedCombos(); + } + + public void testDiffServAndTypeServiceMutuallyExclusive() { + String msg = "It should not be possible to set both Differentiated " + + "Services and Type of Service options on the same connection " + + "URI."; + testInvalidOptionsDoNotWork(TOS + 32 + DIFF_SERV, msg); + testInvalidOptionsDoNotWork(DIFF_SERV + 32 + TOS + 32, msg); + } + + public void initCombosForTestBadVersionNumberDoesNotWork() { + initSharedCombos(); + } + + public void testBadVersionNumberDoesNotWork() throws Exception { + testInvalidOptionsDoNotWork("&minmumWireFormatVersion=65535", ""); + } + + public void initCombosForTestBadPropertyNameFails() { + initSharedCombos(); + } + + public void testBadPropertyNameFails() throws Exception { + testInvalidOptionsDoNotWork("&cheese=abc", ""); + } + + private void initSharedCombos() { + addCombinationValues("prefix", new Object[] {""}); + // TODO: Add more combinations. + addCombinationValues("postfix", new Object[] + {"?tcpNoDelay=true&keepAlive=true&soLinger=0"}); + addCombinationValues("postfix", new Object[] + {"?tcpNoDelay=true&keepAlive=true&soLinger=-1"}); + } + + private void testValidOptionsWork(String options, String msg) { + String uri = prefix + bindAddress + postfix + options; + LOG.info("Connecting via: " + uri); + + try { + connection = new ActiveMQConnectionFactory(uri).createConnection(); + connection.start(); + } catch (Exception unexpected) { + fail("Valid options '" + options + "' on URI '" + uri + "' should " + + "not have caused an exception to be thrown. " + msg + + " Exception: " + unexpected); + } + } + + private void testInvalidOptionsDoNotWork(String options, String msg) { + String uri = prefix + bindAddress + postfix + options; + LOG.info("Connecting via: " + uri); + + try { + connection = new ActiveMQConnectionFactory(uri).createConnection(); + connection.start(); + fail("Invalid options '" + options + "' on URI '" + uri + "' should" + + " have caused an exception to be thrown. " + msg); + } catch (Exception expected) { + } + } + + @Override + protected void setUp() throws Exception { + bindAddress = "tcp://localhost:61616"; + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + try { + connection.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + super.tearDown(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setUseJmx(false); + answer.setPersistent(isPersistent()); + answer.addConnector(bindAddress); + return answer; + } + + public static Test suite() { + return suite(TransportUriTest.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/WireformatNegociationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/WireformatNegociationTest.java new file mode 100644 index 0000000000..70cfa0ea71 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/WireformatNegociationTest.java @@ -0,0 +1,236 @@ +/** + * 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.transport.tcp; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.command.CommandTypes; +import org.apache.activemq.command.WireFormatInfo; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportAcceptListener; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.transport.TransportServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WireformatNegociationTest extends CombinationTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(WireformatNegociationTest.class); + + private TransportServer server; + private Transport clientTransport; + private Transport serverTransport; + + private final AtomicReference clientWF = new AtomicReference(); + private final AtomicReference serverWF = new AtomicReference(); + private final AtomicReference asyncError = new AtomicReference(); + private final AtomicBoolean ignoreAsycError = new AtomicBoolean(); + + private final CountDownLatch negociationCounter = new CountDownLatch(2); + + protected void setUp() throws Exception { + super.setUp(); + } + + /** + * @throws Exception + * @throws URISyntaxException + */ + private void startClient(String uri) throws Exception, URISyntaxException { + clientTransport = TransportFactory.connect(new URI(uri)); + clientTransport.setTransportListener(new TransportListener() { + public void onCommand(Object command) { + if (command instanceof WireFormatInfo) { + clientWF.set((WireFormatInfo)command); + negociationCounter.countDown(); + } + } + + public void onException(IOException error) { + if (!ignoreAsycError.get()) { + LOG.info("Client transport error: ", error); + asyncError.set(error); + negociationCounter.countDown(); + } + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + clientTransport.start(); + } + + /** + * @throws IOException + * @throws URISyntaxException + * @throws Exception + */ + private void startServer(String uri) throws IOException, URISyntaxException, Exception { + server = TransportFactory.bind(new URI(uri)); + server.setAcceptListener(new TransportAcceptListener() { + public void onAccept(Transport transport) { + try { + LOG.info("[" + getName() + "] Server Accepted a Connection"); + serverTransport = transport; + serverTransport.setTransportListener(new TransportListener() { + public void onCommand(Object command) { + if (command instanceof WireFormatInfo) { + serverWF.set((WireFormatInfo)command); + negociationCounter.countDown(); + } + } + + public void onException(IOException error) { + if (!ignoreAsycError.get()) { + LOG.info("Server transport error: ", error); + asyncError.set(error); + negociationCounter.countDown(); + } + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + serverTransport.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void onAcceptError(Exception error) { + error.printStackTrace(); + } + }); + server.start(); + } + + protected void tearDown() throws Exception { + ignoreAsycError.set(true); + try { + if (clientTransport != null) { + clientTransport.stop(); + } + if (serverTransport != null) { + serverTransport.stop(); + } + if (server != null) { + server.stop(); + } + } catch (Throwable e) { + e.printStackTrace(); + } + super.tearDown(); + } + + /** + * @throws Exception + */ + public void testWireFormatInfoSeverVersion1() throws Exception { + + startServer("tcp://localhost:61616?wireFormat.version=1"); + startClient("tcp://localhost:61616"); + + assertTrue("Connect timeout", negociationCounter.await(10, TimeUnit.SECONDS)); + assertNull("Async error: " + asyncError, asyncError.get()); + + assertNotNull(clientWF.get()); + assertEquals(1, clientWF.get().getVersion()); + + assertNotNull(serverWF.get()); + assertEquals(1, serverWF.get().getVersion()); + } + + /** + * @throws Exception + */ + public void testWireFormatInfoClientVersion1() throws Exception { + + startServer("tcp://localhost:61616"); + startClient("tcp://localhost:61616?wireFormat.version=1"); + + assertTrue("Connect timeout", negociationCounter.await(10, TimeUnit.SECONDS)); + assertNull("Async error: " + asyncError, asyncError.get()); + + assertNotNull(clientWF.get()); + assertEquals(1, clientWF.get().getVersion()); + + assertNotNull(serverWF.get()); + assertEquals(1, serverWF.get().getVersion()); + } + + /** + * @throws Exception + */ + public void testWireFormatInfoCurrentVersion() throws Exception { + + startServer("tcp://localhost:61616"); + startClient("tcp://localhost:61616"); + + assertTrue("Connect timeout", negociationCounter.await(10, TimeUnit.SECONDS)); + assertNull("Async error: " + asyncError, asyncError.get()); + + assertNotNull(clientWF.get()); + assertEquals(CommandTypes.PROTOCOL_VERSION, clientWF.get().getVersion()); + + assertNotNull(serverWF.get()); + assertEquals(CommandTypes.PROTOCOL_VERSION, serverWF.get().getVersion()); + } + + public void testWireFormatInactivityDurationInitialDelay() throws Exception { + + startServer("tcp://localhost:61616"); + startClient("tcp://localhost:61616?wireFormat.maxInactivityDurationInitalDelay=60000"); + + assertTrue("Connect timeout", negociationCounter.await(10, TimeUnit.SECONDS)); + assertNull("Async error: " + asyncError, asyncError.get()); + + assertNotNull(clientWF.get()); + assertEquals(CommandTypes.PROTOCOL_VERSION, clientWF.get().getVersion()); + + assertNotNull(serverWF.get()); + assertEquals(CommandTypes.PROTOCOL_VERSION, serverWF.get().getVersion()); + } + + public void testWireFormatMaxFrameSize() throws Exception { + + startServer("tcp://localhost:61616"); + startClient("tcp://localhost:61616?wireFormat.maxFrameSize=1048576"); + + assertTrue("Connect timeout", negociationCounter.await(10, TimeUnit.SECONDS)); + assertNull("Async error: " + asyncError, asyncError.get()); + + assertNotNull(clientWF.get()); + assertEquals(1048576, clientWF.get().getMaxFrameSize()); + + assertNotNull(serverWF.get()); + assertEquals(1048576, serverWF.get().getMaxFrameSize()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/activemq-ssl.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/activemq-ssl.xml new file mode 100644 index 0000000000..1fe92a9df7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/activemq-ssl.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/n-brokers-ssl.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/n-brokers-ssl.xml new file mode 100644 index 0000000000..0cb2f7ee5e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/tcp/n-brokers-ssl.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpSendReceiveWithTwoConnectionsAndLargeMessagesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpSendReceiveWithTwoConnectionsAndLargeMessagesTest.java new file mode 100644 index 0000000000..01d69b4796 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpSendReceiveWithTwoConnectionsAndLargeMessagesTest.java @@ -0,0 +1,31 @@ +/** + * 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.transport.udp; + +/** + * + * + */ +public class UdpSendReceiveWithTwoConnectionsAndLargeMessagesTest extends UdpSendReceiveWithTwoConnectionsTest { + + protected void setUp() throws Exception { + largeMessages = true; + messageCount = 2; + super.setUp(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpSendReceiveWithTwoConnectionsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpSendReceiveWithTwoConnectionsTest.java new file mode 100644 index 0000000000..9ddd5ab31b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpSendReceiveWithTwoConnectionsTest.java @@ -0,0 +1,56 @@ +/** + * 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.transport.udp; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; + +/** + * @version + */ +public class UdpSendReceiveWithTwoConnectionsTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + + protected String brokerURI = "udp://localhost:8891"; + protected BrokerService broker; + + protected void setUp() throws Exception { + broker = createBroker(); + broker.start(); + + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (broker != null) { + broker.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.setUseJmx(false); + answer.addConnector(brokerURI); + return answer; + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(brokerURI); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTestSupport.java new file mode 100644 index 0000000000..1d770de24e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTestSupport.java @@ -0,0 +1,272 @@ +/** + * 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.transport.udp; + +import java.io.IOException; + +import javax.jms.MessageNotWriteableException; + +import junit.framework.TestCase; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.command.Command; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.Response; +import org.apache.activemq.command.WireFormatInfo; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportAcceptListener; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.transport.TransportServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public abstract class UdpTestSupport extends TestCase implements TransportListener { + + private static final Logger LOG = LoggerFactory.getLogger(UdpTestSupport.class); + + protected Transport producer; + protected Transport consumer; + + protected Object lock = new Object(); + protected Command receivedCommand; + protected TransportServer server; + protected boolean large; + + // You might want to set this to massive number if debugging + protected int waitForCommandTimeout = 40000; + + public void testSendingSmallMessage() throws Exception { + ConsumerInfo expected = new ConsumerInfo(); + expected.setSelector("Cheese"); + expected.setExclusive(true); + expected.setExclusive(true); + expected.setPrefetchSize(3456); + + try { + LOG.info("About to send: " + expected); + producer.oneway(expected); + + Command received = assertCommandReceived(); + assertTrue("Should have received a ConsumerInfo but was: " + received, received instanceof ConsumerInfo); + ConsumerInfo actual = (ConsumerInfo)received; + assertEquals("Selector", expected.getSelector(), actual.getSelector()); + assertEquals("isExclusive", expected.isExclusive(), actual.isExclusive()); + assertEquals("getPrefetchSize", expected.getPrefetchSize(), actual.getPrefetchSize()); + } catch (Exception e) { + LOG.info("Caught: " + e); + e.printStackTrace(); + fail("Failed to send to transport: " + e); + } + } + + public void testSendingMediumMessage() throws Exception { + String text = createMessageBodyText(4 * 105); + ActiveMQDestination destination = new ActiveMQQueue("Foo.Bar.Medium"); + assertSendTextMessage(destination, text); + } + + public void testSendingLargeMessage() throws Exception { + String text = createMessageBodyText(4 * 1024); + ActiveMQDestination destination = new ActiveMQQueue("Foo.Bar.Large"); + assertSendTextMessage(destination, text); + } + + protected void assertSendTextMessage(ActiveMQDestination destination, String text) throws MessageNotWriteableException { + large = true; + + ActiveMQTextMessage expected = new ActiveMQTextMessage(); + + expected.setText(text); + expected.setDestination(destination); + + try { + LOG.info("About to send message of type: " + expected.getClass()); + producer.oneway(expected); + + // lets send a dummy command to ensure things don't block if we + // discard the last one + // keepalive does not have a commandId... + // producer.oneway(new KeepAliveInfo()); + producer.oneway(new ProducerInfo()); + producer.oneway(new ProducerInfo()); + + Command received = assertCommandReceived(); + assertTrue("Should have received a ActiveMQTextMessage but was: " + received, received instanceof ActiveMQTextMessage); + ActiveMQTextMessage actual = (ActiveMQTextMessage)received; + + assertEquals("getDestination", expected.getDestination(), actual.getDestination()); + assertEquals("getText", expected.getText(), actual.getText()); + + LOG.info("Received text message with: " + actual.getText().length() + " character(s)"); + } catch (Exception e) { + LOG.info("Caught: " + e); + e.printStackTrace(); + fail("Failed to send to transport: " + e); + } + } + + protected String createMessageBodyText(int loopSize) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < loopSize; i++) { + buffer.append("0123456789"); + } + return buffer.toString(); + } + + protected void setUp() throws Exception { + server = createServer(); + if (server != null) { + server.setAcceptListener(new TransportAcceptListener() { + + public void onAccept(Transport transport) { + consumer = transport; + consumer.setTransportListener(UdpTestSupport.this); + try { + consumer.start(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void onAcceptError(Exception error) { + } + }); + server.start(); + } + + consumer = createConsumer(); + if (consumer != null) { + consumer.setTransportListener(this); + consumer.start(); + } + + producer = createProducer(); + producer.setTransportListener(new TransportListener() { + public void onCommand(Object command) { + LOG.info("Producer received: " + command); + } + + public void onException(IOException error) { + LOG.info("Producer exception: " + error); + error.printStackTrace(); + } + + public void transportInterupted() { + } + + public void transportResumed() { + } + }); + + producer.start(); + } + + protected void tearDown() throws Exception { + if (producer != null) { + try { + producer.stop(); + } catch (Exception e) { + } + } + if (consumer != null) { + consumer.stop(); + } + if (server != null) { + server.stop(); + } + } + + public void onCommand(Object o) { + final Command command = (Command)o; + if (command instanceof WireFormatInfo) { + LOG.info("Got WireFormatInfo: " + command); + } else { + if (command.isResponseRequired()) { + // lets send a response back... + sendResponse(command); + + } + if (large) { + LOG.info("### Received command: " + command.getClass() + " with id: " + command.getCommandId()); + } else { + LOG.info("### Received command: " + command); + } + + synchronized (lock) { + if (receivedCommand == null) { + receivedCommand = command; + } else { + LOG.info("Ignoring superfluous command: " + command); + } + lock.notifyAll(); + } + } + } + + protected void sendResponse(Command command) { + Response response = new Response(); + response.setCorrelationId(command.getCommandId()); + try { + consumer.oneway(response); + } catch (IOException e) { + LOG.info("Caught: " + e); + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public void onException(IOException error) { + LOG.info("### Received error: " + error); + error.printStackTrace(); + } + + public void transportInterupted() { + LOG.info("### Transport interrupted"); + } + + public void transportResumed() { + LOG.info("### Transport resumed"); + } + + protected Command assertCommandReceived() throws InterruptedException { + Command answer = null; + synchronized (lock) { + answer = receivedCommand; + if (answer == null) { + lock.wait(waitForCommandTimeout); + } + answer = receivedCommand; + } + + assertNotNull("Should have received a Command by now!", answer); + return answer; + } + + protected abstract Transport createConsumer() throws Exception; + + protected abstract Transport createProducer() throws Exception; + + protected TransportServer createServer() throws Exception { + return null; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTransportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTransportTest.java new file mode 100644 index 0000000000..98ea8f188b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTransportTest.java @@ -0,0 +1,64 @@ +/** + * 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.transport.udp; + +import java.net.URI; + +import org.apache.activemq.openwire.OpenWireFormat; +import org.apache.activemq.transport.CommandJoiner; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.util.IntSequenceGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class UdpTransportTest extends UdpTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(UdpTransportTest.class); + + protected int consumerPort = 9123; + protected String producerURI = "udp://localhost:" + consumerPort; + + protected Transport createProducer() throws Exception { + LOG.info("Producer using URI: " + producerURI); + + // we are not using the TransportFactory as this assumes that + // UDP transports talk to a server using a WireFormat Negotiation step + // rather than talking directly to each other + + OpenWireFormat wireFormat = createWireFormat(); + UdpTransport transport = new UdpTransport(wireFormat, new URI(producerURI)); + transport.setSequenceGenerator(new IntSequenceGenerator()); + return new CommandJoiner(transport, wireFormat); + } + + protected Transport createConsumer() throws Exception { + LOG.info("Consumer on port: " + consumerPort); + OpenWireFormat wireFormat = createWireFormat(); + UdpTransport transport = new UdpTransport(wireFormat, consumerPort); + transport.setSequenceGenerator(new IntSequenceGenerator()); + return new CommandJoiner(transport, wireFormat); + } + + protected OpenWireFormat createWireFormat() { + return new OpenWireFormat(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTransportUsingServerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTransportUsingServerTest.java new file mode 100644 index 0000000000..bd9d9637a7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UdpTransportUsingServerTest.java @@ -0,0 +1,66 @@ +/** + * 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.transport.udp; + +import java.net.URI; + +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Response; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportServer; +import org.apache.activemq.transport.tcp.WireformatNegociationTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class UdpTransportUsingServerTest extends UdpTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(UdpTransportUsingServerTest.class); + + protected int consumerPort = 9123; + protected String producerURI = "udp://localhost:" + consumerPort; + protected String serverURI = producerURI; + + public void testRequestResponse() throws Exception { + ConsumerInfo expected = new ConsumerInfo(); + expected.setSelector("Edam"); + expected.setResponseRequired(true); + LOG.info("About to send: " + expected); + Response response = (Response) producer.request(expected, 2000); + + LOG.info("Received: " + response); + assertNotNull("Received a response", response); + assertTrue("Should not be an exception", !response.isException()); + } + + protected Transport createProducer() throws Exception { + LOG.info("Producer using URI: " + producerURI); + URI uri = new URI(producerURI); + return TransportFactory.connect(uri); + } + + protected TransportServer createServer() throws Exception { + return TransportFactory.bind(new URI(serverURI)); + } + + protected Transport createConsumer() throws Exception { + return null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UpdTransportBindTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UpdTransportBindTest.java new file mode 100644 index 0000000000..943b0439c6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/udp/UpdTransportBindTest.java @@ -0,0 +1,43 @@ +/** + * 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.transport.udp; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; + +import javax.jms.Connection; +import javax.jms.JMSException; + +public class UpdTransportBindTest extends EmbeddedBrokerTestSupport{ + final String addr = "udp://localhost:61625"; + + protected void setUp() throws Exception { + bindAddress = addr + "?soTimeout=1000"; + super.setUp(); + } + + public void testConnect() throws Exception { + try { + Connection connection = new ActiveMQConnectionFactory(addr).createConnection(); + connection.start(); + } catch (JMSException e) { + fail("Could not start the connection for a UDP Transport. " + + "Check that the port and connector are available."); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportBrokerNameTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportBrokerNameTest.java new file mode 100644 index 0000000000..ac0539317a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportBrokerNameTest.java @@ -0,0 +1,50 @@ +/** + * 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.transport.vm; + +import java.net.URI; + +import javax.jms.Connection; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerRegistry; + +public class VMTransportBrokerNameTest extends TestCase { + + private static final String MY_BROKER = "myBroker"; + final String vmUrl = "vm:(broker:(tcp://localhost:61616)/" + MY_BROKER + "?persistent=false)"; + + public void testBrokerName() throws Exception { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(new URI(vmUrl)); + ActiveMQConnection c1 = (ActiveMQConnection) cf.createConnection(); + assertTrue("Transport has name in it: " + c1.getTransport(), c1.getTransport().toString().contains(MY_BROKER)); + + // verify Broker is there with name + ActiveMQConnectionFactory cfbyName = new ActiveMQConnectionFactory(new URI("vm://" + MY_BROKER + "?create=false")); + Connection c2 = cfbyName.createConnection(); + + assertNotNull(BrokerRegistry.getInstance().lookup(MY_BROKER)); + assertEquals(BrokerRegistry.getInstance().findFirst().getBrokerName(), MY_BROKER); + assertEquals(BrokerRegistry.getInstance().getBrokers().size(), 1); + + c1.close(); + c2.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportBrokerTest.java new file mode 100644 index 0000000000..c4f9ab2063 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportBrokerTest.java @@ -0,0 +1,37 @@ +/** + * 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.transport.vm; + +import junit.framework.Test; +import org.apache.activemq.transport.TransportBrokerTestSupport; + +public class VMTransportBrokerTest extends TransportBrokerTestSupport { + + protected String getBindLocation() { + return "vm://localhost"; + } + + public static Test suite() { + return suite(VMTransportBrokerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportEmbeddedBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportEmbeddedBrokerTest.java new file mode 100644 index 0000000000..62e4f71538 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportEmbeddedBrokerTest.java @@ -0,0 +1,100 @@ +/** + * 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.transport.vm; + +import java.net.URI; +import java.net.URISyntaxException; + +import javax.jms.DeliveryMode; + +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerTestSupport; +import org.apache.activemq.broker.StubConnection; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.Message; +import org.apache.activemq.command.ProducerInfo; +import org.apache.activemq.command.SessionInfo; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.util.IOExceptionSupport; + +/** + * Used to see if the VM transport starts an embedded broker on demand. + * + * + */ +public class VMTransportEmbeddedBrokerTest extends BrokerTestSupport { + + public static void main(String[] args) { + junit.textui.TestRunner.run(VMTransportEmbeddedBrokerTest.class); + } + + public void testConsumerPrefetchAtOne() throws Exception { + + // Make sure the broker is created due to the connection being started. + assertNull(BrokerRegistry.getInstance().lookup("localhost")); + StubConnection connection = createConnection(); + assertNotNull(BrokerRegistry.getInstance().lookup("localhost")); + + // Start a producer and consumer + ConnectionInfo connectionInfo = createConnectionInfo(); + SessionInfo sessionInfo = createSessionInfo(connectionInfo); + ProducerInfo producerInfo = createProducerInfo(sessionInfo); + connection.send(connectionInfo); + connection.send(sessionInfo); + connection.send(producerInfo); + + ActiveMQQueue destination = new ActiveMQQueue("TEST"); + + ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); + consumerInfo.setPrefetchSize(1); + connection.send(consumerInfo); + + // Send 2 messages to the broker. + connection.send(createMessage(producerInfo, destination, DeliveryMode.NON_PERSISTENT)); + connection.send(createMessage(producerInfo, destination, DeliveryMode.NON_PERSISTENT)); + + // Make sure only 1 message was delivered. + Message m = receiveMessage(connection); + assertNotNull(m); + assertNoMessagesLeft(connection); + + // Make sure the broker is shutdown when the connection is stopped. + assertNotNull(BrokerRegistry.getInstance().lookup("localhost")); + connection.stop(); + assertNull(BrokerRegistry.getInstance().lookup("localhost")); + } + + protected void setUp() throws Exception { + // Don't call super since it manually starts up a broker. + } + protected void tearDown() throws Exception { + // Don't call super since it manually tears down a broker. + } + protected StubConnection createConnection() throws Exception { + try { + Transport transport = TransportFactory.connect(new URI("vm://localhost?broker.persistent=false")); + StubConnection connection = new StubConnection(transport); + return connection; + } catch (URISyntaxException e) { + throw IOExceptionSupport.create(e); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportThreadSafeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportThreadSafeTest.java new file mode 100644 index 0000000000..8534f8908a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportThreadSafeTest.java @@ -0,0 +1,920 @@ +/** + * 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.transport.vm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.URI; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.activemq.command.BaseCommand; +import org.apache.activemq.command.ExceptionResponse; +import org.apache.activemq.command.Response; +import org.apache.activemq.command.ShutdownInfo; +import org.apache.activemq.state.CommandVisitor; +import org.apache.activemq.transport.FutureResponse; +import org.apache.activemq.transport.MutexTransport; +import org.apache.activemq.transport.ResponseCallback; +import org.apache.activemq.transport.ResponseCorrelator; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportDisposedIOException; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VMTransportThreadSafeTest { + + private static final Logger LOG = LoggerFactory.getLogger(VMTransportThreadSafeTest.class); + + private final static String location1 = "vm://transport1"; + private final static String location2 = "vm://transport2"; + + private final ConcurrentLinkedQueue localReceived = new ConcurrentLinkedQueue(); + private final ConcurrentLinkedQueue remoteReceived = new ConcurrentLinkedQueue(); + + private class DummyCommand extends BaseCommand { + + public final int sequenceId; + + public DummyCommand() { + this.sequenceId = 0; + } + + public DummyCommand(int id) { + this.sequenceId = id; + } + + @Override + public Response visit(CommandVisitor visitor) throws Exception { + return null; + } + + @Override + public byte getDataStructureType() { + return 42; + } + } + + private class VMTestTransportListener implements TransportListener { + + protected final Queue received; + + public boolean shutdownReceived = false; + + public VMTestTransportListener(Queue receiveQueue) { + this.received = receiveQueue; + } + + @Override + public void onCommand(Object command) { + + if (command instanceof ShutdownInfo) { + shutdownReceived = true; + } else { + received.add((DummyCommand) command); + } + } + + @Override + public void onException(IOException error) { + } + + @Override + public void transportInterupted() { + } + + @Override + public void transportResumed() { + } + } + + private class VMResponderTransportListener implements TransportListener { + + protected final Queue received; + + private final Transport peer; + + public VMResponderTransportListener(Queue receiveQueue, Transport peer) { + this.received = receiveQueue; + this.peer = peer; + } + + @Override + public void onCommand(Object command) { + + if (command instanceof ShutdownInfo) { + return; + } else { + received.add((DummyCommand) command); + + if (peer != null) { + try { + peer.oneway(command); + } catch (IOException e) { + } + } + } + } + + @Override + public void onException(IOException error) { + } + + @Override + public void transportInterupted() { + } + + @Override + public void transportResumed() { + } + } + + private class SlowVMTestTransportListener extends VMTestTransportListener { + + private final TimeUnit delayUnit; + private final long delay; + + public SlowVMTestTransportListener(Queue receiveQueue) { + this(receiveQueue, 10, TimeUnit.MILLISECONDS); + } + + public SlowVMTestTransportListener(Queue receiveQueue, long delay, TimeUnit delayUnit) { + super(receiveQueue); + + this.delay = delay; + this.delayUnit = delayUnit; + } + + @Override + public void onCommand(Object command) { + super.onCommand(command); + try { + delayUnit.sleep(delay); + } catch (InterruptedException e) { + } + } + } + + private class GatedVMTestTransportListener extends VMTestTransportListener { + + private final CountDownLatch gate; + + public GatedVMTestTransportListener(Queue receiveQueue) { + this(receiveQueue, new CountDownLatch(1)); + } + + public GatedVMTestTransportListener(Queue receiveQueue, CountDownLatch gate) { + super(receiveQueue); + + this.gate = gate; + } + + @Override + public void onCommand(Object command) { + super.onCommand(command); + try { + gate.await(); + } catch (InterruptedException e) { + } + } + } + + private void assertMessageAreOrdered(ConcurrentLinkedQueue queue) { + int lastSequenceId = 0; + for(DummyCommand command : queue) { + int id = command.sequenceId; + assertTrue("Last id: " + lastSequenceId + " should be less than current id: " + id, id > lastSequenceId); + } + } + + @Before + public void setUp() throws Exception { + localReceived.clear(); + remoteReceived.clear(); + } + + @After + public void tearDown() throws Exception { + } + + @Test(timeout=60000) + public void testStartWthoutListenerIOE() throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + local.setPeer(remote); + remote.setPeer(local); + + remote.setTransportListener(new VMTestTransportListener(localReceived)); + + try { + local.start(); + fail("Should have thrown an IOExcoption"); + } catch (IOException e) { + } + } + + @Test(timeout=60000) + public void testOnewayOnStoppedTransportTDE() throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new VMTestTransportListener(remoteReceived)); + + local.start(); + local.stop(); + + try { + local.oneway(new DummyCommand()); + fail("Should have thrown a TransportDisposedException"); + } catch(TransportDisposedIOException e) { + } + } + + @Test(timeout=60000) + public void testStopSendsShutdownToPeer() throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + local.setPeer(remote); + remote.setPeer(local); + + final VMTestTransportListener remoteListener = new VMTestTransportListener(remoteReceived); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(remoteListener); + + local.start(); + local.stop(); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remoteListener.shutdownReceived; + } + })); + } + + @Test(timeout=60000) + public void testRemoteStopSendsExceptionToPendingRequests() throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + local.setPeer(remote); + remote.setPeer(local); + + final VMTestTransportListener remoteListener = new VMTestTransportListener(remoteReceived); + remote.setTransportListener(remoteListener); + remote.start(); + + final Response[] answer = new Response[1]; + ResponseCorrelator responseCorrelator = new ResponseCorrelator(local); + responseCorrelator.setTransportListener(new VMTestTransportListener(localReceived)); + responseCorrelator.start(); + responseCorrelator.asyncRequest(new DummyCommand(), new ResponseCallback() { + @Override + public void onCompletion(FutureResponse resp) { + try { + answer[0] = resp.getResult(); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + + // simulate broker stop + remote.stop(); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("answer: " + answer[0]); + return answer[0] instanceof ExceptionResponse && ((ExceptionResponse)answer[0]).getException() instanceof TransportDisposedIOException; + } + })); + + local.stop(); + } + + @Test(timeout=60000) + public void testMultipleStartsAndStops() throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new VMTestTransportListener(remoteReceived)); + + local.start(); + remote.start(); + + local.start(); + remote.start(); + + for(int i = 0; i < 100; ++i) { + local.oneway(new DummyCommand()); + } + + for(int i = 0; i < 100; ++i) { + remote.oneway(new DummyCommand()); + } + + local.start(); + remote.start(); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remoteReceived.size() == 100; + } + })); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return localReceived.size() == 100; + } + })); + + local.stop(); + local.stop(); + remote.stop(); + remote.stop(); + } + + @Test(timeout=60000) + public void testStartWithPeerNotStartedEnqueusCommandsNonAsync() throws Exception { + doTestStartWithPeerNotStartedEnqueusCommands(false); + } + + private void doTestStartWithPeerNotStartedEnqueusCommands(boolean async) throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + remote.setAsync(async); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new VMTestTransportListener(remoteReceived)); + + local.start(); + + for(int i = 0; i < 100; ++i) { + local.oneway(new DummyCommand()); + } + + assertEquals(100, remote.getMessageQueue().size()); + + remote.start(); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remoteReceived.size() == 100; + } + })); + + local.stop(); + remote.stop(); + } + + @Test(timeout=60000) + public void testBlockedOnewayEnqeueAandStopTransportAsync() throws Exception { + doTestBlockedOnewayEnqeueAandStopTransport(true); + } + + @Test(timeout=60000) + public void testBlockedOnewayEnqeueAandStopTransportNonAsync() throws Exception { + doTestBlockedOnewayEnqeueAandStopTransport(false); + } + + private void doTestBlockedOnewayEnqeueAandStopTransport(boolean async) throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + final AtomicInteger sequenceId = new AtomicInteger(); + + remote.setAsync(async); + remote.setAsyncQueueDepth(99); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new VMTestTransportListener(remoteReceived)); + + local.start(); + + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + for(int i = 0; i < 100; ++i) { + try { + local.oneway(new DummyCommand(sequenceId.incrementAndGet())); + } catch (Exception e) { + } + } + + } + }); + t.start(); + + LOG.debug("Started async delivery, wait for remote's queue to fill up"); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remote.getMessageQueue().remainingCapacity() == 0; + } + })); + + LOG.debug("Remote messageQ is full, start it and stop all"); + + remote.start(); + local.stop(); + remote.stop(); + } + + @Test(timeout=60000) + public void testBlockedOnewayEnqeueWhileStartedDetectsStop() throws Exception { + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + final AtomicInteger sequenceId = new AtomicInteger(); + + remote.setAsync(true); + remote.setAsyncQueueDepth(2); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new GatedVMTestTransportListener(remoteReceived)); + + local.start(); + remote.start(); + + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + for(int i = 0; i < 3; ++i) { + try { + local.oneway(new DummyCommand(sequenceId.incrementAndGet())); + } catch (Exception e) { + } + } + + } + }); + t.start(); + + LOG.debug("Started async delivery, wait for remote's queue to fill up"); + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remote.getMessageQueue().remainingCapacity() == 0; + } + })); + + LOG.debug("Starting async gate open."); + Thread gateman = new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + ((GatedVMTestTransportListener) remote.getTransportListener()).gate.countDown(); + } + }); + gateman.start(); + + remote.stop(); + local.stop(); + + assertEquals(1, remoteReceived.size()); + assertMessageAreOrdered(remoteReceived); + } + + @Test(timeout=60000) + public void testStopWhileStartingAsyncWithNoAsyncLimit() throws Exception { + // In the async case the iterate method should see that we are stopping and + // drop out before we dispatch all the messages but it should get at least 49 since + // the stop thread waits 500 mills and the listener is waiting 10 mills on each receive. + doTestStopWhileStartingWithNoAsyncLimit(true, 49); + } + + @Test(timeout=60000) + public void testStopWhileStartingNonAsyncWithNoAsyncLimit() throws Exception { + // In the non-async case the start dispatches all messages up front and then continues on + doTestStopWhileStartingWithNoAsyncLimit(false, 100); + } + + private void doTestStopWhileStartingWithNoAsyncLimit(boolean async, final int expect) throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + remote.setAsync(async); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new SlowVMTestTransportListener(remoteReceived)); + + local.start(); + + for(int i = 0; i < 100; ++i) { + local.oneway(new DummyCommand(i)); + } + + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + try { + Thread.sleep(1000); + remote.stop(); + } catch (Exception e) { + } + } + }); + + remote.start(); + + t.start(); + + assertTrue("Remote should receive: " + expect + ", commands but got: " + remoteReceived.size(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remoteReceived.size() >= expect; + } + })); + + LOG.debug("Remote listener received " + remoteReceived.size() + " messages"); + + local.stop(); + + assertTrue("Remote transport never was disposed.", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remote.isDisposed(); + } + })); + } + + @Test(timeout=120000) + public void TestTwoWayMessageThroughPutSync() throws Exception { + + long totalTimes = 0; + final long executions = 20; + + for (int i = 0; i < 20; ++i) { + totalTimes += doTestTwoWayMessageThroughPut(false); + } + + LOG.info("Total time of one way sync send throughput test: " + (totalTimes/executions) + "ms"); + } + + @Test(timeout=120000) + public void TestTwoWayMessageThroughPutAsnyc() throws Exception { + + long totalTimes = 0; + final long executions = 50; + + for (int i = 0; i < executions; ++i) { + totalTimes += doTestTwoWayMessageThroughPut(false); + } + + LOG.info("Total time of one way async send throughput test: " + (totalTimes/executions) + "ms"); + } + + private long doTestTwoWayMessageThroughPut(boolean async) throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + final AtomicInteger sequenceId = new AtomicInteger(); + + remote.setAsync(async); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new VMTestTransportListener(remoteReceived)); + + final int messageCount = 200000; + + local.start(); + remote.start(); + + long startTime = System.currentTimeMillis(); + + Thread localSend = new Thread(new Runnable() { + + @Override + public void run() { + for(int i = 0; i < messageCount; ++i) { + try { + local.oneway(new DummyCommand(sequenceId.incrementAndGet())); + } catch (Exception e) { + } + } + + } + }); + + Thread remoteSend = new Thread(new Runnable() { + + @Override + public void run() { + for(int i = 0; i < messageCount; ++i) { + try { + remote.oneway(new DummyCommand(sequenceId.incrementAndGet())); + } catch (Exception e) { + } + } + + } + }); + + localSend.start(); + remoteSend.start(); + + // Wait for both to finish and then check that each side go the correct amount + localSend.join(); + remoteSend.join(); + + long endTime = System.currentTimeMillis(); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remoteReceived.size() == messageCount; + } + })); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return localReceived.size() == messageCount; + } + })); + + LOG.debug("All messages sent,stop all"); + + local.stop(); + remote.stop(); + + localReceived.clear(); + remoteReceived.clear(); + + return endTime - startTime; + } + + @Test(timeout=120000) + public void TestOneWayMessageThroughPutSync() throws Exception { + + long totalTimes = 0; + final long executions = 30; + + for (int i = 0; i < executions; ++i) { + totalTimes += doTestOneWayMessageThroughPut(false); + } + + LOG.info("Total time of one way sync send throughput test: " + (totalTimes/executions) + "ms"); + } + + @Test(timeout=120000) + public void TestOneWayMessageThroughPutAsnyc() throws Exception { + + long totalTimes = 0; + final long executions = 20; + + for (int i = 0; i < 20; ++i) { + totalTimes += doTestOneWayMessageThroughPut(true); + } + + LOG.info("Total time of one way async send throughput test: " + (totalTimes/executions) + "ms"); + } + + private long doTestOneWayMessageThroughPut(boolean async) throws Exception { + + final VMTransport local = new VMTransport(new URI(location1)); + final VMTransport remote = new VMTransport(new URI(location2)); + + final AtomicInteger sequenceId = new AtomicInteger(); + + remote.setAsync(async); + + local.setPeer(remote); + remote.setPeer(local); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new VMTestTransportListener(remoteReceived)); + + final int messageCount = 100000; + + local.start(); + remote.start(); + + long startTime = System.currentTimeMillis(); + + Thread localSend = new Thread(new Runnable() { + + @Override + public void run() { + for(int i = 0; i < messageCount; ++i) { + try { + local.oneway(new DummyCommand(sequenceId.incrementAndGet())); + } catch (Exception e) { + } + } + + } + }); + + localSend.start(); + + // Wait for both to finish and then check that each side go the correct amount + localSend.join(); + + long endTime = System.currentTimeMillis(); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remoteReceived.size() == messageCount; + } + })); + + LOG.debug("All messages sent,stop all"); + + local.stop(); + remote.stop(); + + localReceived.clear(); + remoteReceived.clear(); + + return endTime - startTime; + } + + @Test(timeout=120000) + public void testTwoWayTrafficWithMutexTransportSync1() throws Exception { + + for (int i = 0; i < 20; ++i) { + doTestTwoWayTrafficWithMutexTransport(false, false); + } + } + + @Test(timeout=120000) + public void testTwoWayTrafficWithMutexTransportSync2() throws Exception { + + for (int i = 0; i < 20; ++i) { + doTestTwoWayTrafficWithMutexTransport(true, false); + } + } + + @Test(timeout=120000) + public void testTwoWayTrafficWithMutexTransportSync3() throws Exception { + + for (int i = 0; i < 20; ++i) { + doTestTwoWayTrafficWithMutexTransport(false, true); + } + } + + @Test(timeout=120000) + public void testTwoWayTrafficWithMutexTransportSync4() throws Exception { + + for (int i = 0; i < 20; ++i) { + doTestTwoWayTrafficWithMutexTransport(false, false); + } + } + + public void doTestTwoWayTrafficWithMutexTransport(boolean localAsync, boolean remoteAsync) throws Exception { + + final VMTransport vmlocal = new VMTransport(new URI(location1)); + final VMTransport vmremote = new VMTransport(new URI(location2)); + + final MutexTransport local = new MutexTransport(vmlocal); + final MutexTransport remote = new MutexTransport(vmremote); + + final AtomicInteger sequenceId = new AtomicInteger(); + + vmlocal.setAsync(localAsync); + vmremote.setAsync(remoteAsync); + + vmlocal.setPeer(vmremote); + vmremote.setPeer(vmlocal); + + local.setTransportListener(new VMTestTransportListener(localReceived)); + remote.setTransportListener(new VMResponderTransportListener(remoteReceived, remote)); + + final int messageCount = 200000; + + Thread localSend = new Thread(new Runnable() { + + @Override + public void run() { + for(int i = 0; i < messageCount; ++i) { + try { + local.oneway(new DummyCommand(sequenceId.incrementAndGet())); + } catch (Exception e) { + } + } + } + }); + + Thread remoteSend = new Thread(new Runnable() { + + @Override + public void run() { + for(int i = 0; i < messageCount; ++i) { + try { + remote.oneway(new DummyCommand(sequenceId.incrementAndGet())); + } catch (Exception e) { + } + } + } + }); + + localSend.start(); + remoteSend.start(); + + Thread.sleep(10); + + local.start(); + remote.start(); + + // Wait for both to finish and then check that each side go the correct amount + localSend.join(); + remoteSend.join(); + + assertTrue("Remote should have received ("+messageCount+") but got ()" + remoteReceived.size(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return remoteReceived.size() == messageCount; + } + })); + + assertTrue("Local should have received ("+messageCount*2+") but got ()" + localReceived.size(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return localReceived.size() == messageCount*2; + } + })); + + LOG.debug("All messages sent,stop all"); + + local.stop(); + remote.stop(); + + localReceived.clear(); + remoteReceived.clear(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportWaitForTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportWaitForTest.java new file mode 100644 index 0000000000..805a10c6be --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VMTransportWaitForTest.java @@ -0,0 +1,137 @@ +/** + * 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.transport.vm; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.JMSException; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.BrokerService; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VMTransportWaitForTest { + static final Logger LOG = LoggerFactory.getLogger(VMTransportWaitForTest.class); + + private static final int WAIT_TIME = 20000; + private static final int SHORT_WAIT_TIME = 5000; + + private static final String VM_BROKER_URI_NO_WAIT = + "vm://localhost?broker.persistent=false&create=false"; + + private static final String VM_BROKER_URI_WAIT_FOR_START = + VM_BROKER_URI_NO_WAIT + "&waitForStart=" + WAIT_TIME; + + private static final String VM_BROKER_URI_SHORT_WAIT_FOR_START = + VM_BROKER_URI_NO_WAIT + "&waitForStart=" + SHORT_WAIT_TIME; + + CountDownLatch started = new CountDownLatch(1); + CountDownLatch gotConnection = new CountDownLatch(1); + + @After + public void after() throws IOException { + BrokerRegistry.getInstance().unbind("localhost"); + } + + @Test(timeout=90000) + public void testWaitFor() throws Exception { + try { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(new URI(VM_BROKER_URI_NO_WAIT)); + cf.createConnection(); + fail("expect broker not exist exception"); + } catch (JMSException expectedOnNoBrokerAndNoCreate) { + } + + // spawn a thread that will wait for an embedded broker to start via + // vm://.. + Thread t = new Thread("ClientConnectionThread") { + @Override + public void run() { + try { + started.countDown(); + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(new URI(VM_BROKER_URI_WAIT_FOR_START)); + cf.createConnection(); + gotConnection.countDown(); + } catch (Exception e) { + e.printStackTrace(); + fail("unexpected exception: " + e); + } + } + }; + t.start(); + started.await(20, TimeUnit.SECONDS); + Thread.yield(); + assertFalse("has not got connection", gotConnection.await(2, TimeUnit.SECONDS)); + + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.start(); + assertTrue("has got connection", gotConnection.await(5, TimeUnit.SECONDS)); + broker.stop(); + } + + @Test(timeout=90000) + public void testWaitForNoBrokerInRegistry() throws Exception { + + long startTime = System.currentTimeMillis(); + + try { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(new URI(VM_BROKER_URI_SHORT_WAIT_FOR_START)); + cf.createConnection(); + fail("expect broker not exist exception"); + } catch (JMSException expectedOnNoBrokerAndNoCreate) { + } + + long endTime = System.currentTimeMillis(); + + LOG.info("Total wait time was: {}", endTime - startTime); + assertTrue(endTime - startTime >= SHORT_WAIT_TIME - 100); + } + + @Test(timeout=90000) + public void testWaitForNotStartedButInRegistry() throws Exception { + + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + BrokerRegistry.getInstance().bind("localhost", broker); + + long startTime = System.currentTimeMillis(); + + try { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(new URI(VM_BROKER_URI_SHORT_WAIT_FOR_START)); + cf.createConnection(); + fail("expect broker not exist exception"); + } catch (JMSException expectedOnNoBrokerAndNoCreate) { + } + + long endTime = System.currentTimeMillis(); + + LOG.info("Total wait time was: {}", endTime - startTime); + assertTrue(endTime - startTime >= SHORT_WAIT_TIME - 100); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VmTransportNetworkBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VmTransportNetworkBrokerTest.java new file mode 100644 index 0000000000..e29c078e16 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/transport/vm/VmTransportNetworkBrokerTest.java @@ -0,0 +1,155 @@ +/** + * 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.transport.vm; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.bugs.embedded.ThreadExplorer; +import org.apache.activemq.network.NetworkConnector; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class VmTransportNetworkBrokerTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(VmTransportNetworkBrokerTest.class); + + private static final String VM_BROKER_URI = + "vm://localhost?create=false"; + + CountDownLatch started = new CountDownLatch(1); + CountDownLatch gotConnection = new CountDownLatch(1); + + public void testNoThreadLeak() throws Exception { + + // with VMConnection and simple discovery network connector + int originalThreadCount = Thread.activeCount(); + LOG.debug(ThreadExplorer.show("threads at beginning")); + + BrokerService broker = new BrokerService(); + broker.setDedicatedTaskRunner(true); + broker.setPersistent(false); + broker.addConnector("tcp://localhost:61616"); + NetworkConnector networkConnector = broker.addNetworkConnector("static:(tcp://wrongHostname1:61617,tcp://wrongHostname2:61618)?useExponentialBackOff=false"); + networkConnector.setDuplex(true); + broker.start(); + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(new URI(VM_BROKER_URI)); + Connection connection = cf.createConnection("system", "manager"); + connection.start(); + + // let it settle + TimeUnit.SECONDS.sleep(5); + + int threadCountAfterStart = Thread.activeCount(); + TimeUnit.SECONDS.sleep(30); + int threadCountAfterSleep = Thread.activeCount(); + + assertTrue("Threads are leaking: " + ThreadExplorer.show("active sleep") + ", threadCount=" +threadCountAfterStart + " threadCountAfterSleep=" + threadCountAfterSleep, + threadCountAfterSleep < threadCountAfterStart + 8); + + connection.close(); + broker.stop(); + broker.waitUntilStopped(); + + // testNoDanglingThreadsAfterStop with tcp transport + broker = new BrokerService(); + broker.setSchedulerSupport(true); + broker.setDedicatedTaskRunner(true); + broker.setPersistent(false); + broker.addConnector("tcp://localhost:61616?wireFormat.maxInactivityDuration=1000&wireFormat.maxInactivityDurationInitalDelay=1000"); + broker.start(); + + cf = new ActiveMQConnectionFactory("tcp://localhost:61616?wireFormat.maxInactivityDuration=1000&wireFormat.maxInactivityDurationInitalDelay=1000"); + connection = cf.createConnection("system", "manager"); + connection.start(); + connection.close(); + broker.stop(); + broker.waitUntilStopped(); + + // let it settle + TimeUnit.SECONDS.sleep(5); + + // get final threads but filter out any daemon threads that the JVM may have created. + Thread[] threads = filterDaemonThreads(ThreadExplorer.listThreads()); + int threadCountAfterStop = threads.length; + + // lets see the thread counts at INFO level so they are always in the test log + LOG.info(ThreadExplorer.show("active after stop")); + LOG.info("originalThreadCount=" + originalThreadCount + " threadCountAfterStop=" + threadCountAfterStop); + + assertTrue("Threads are leaking: " + + ThreadExplorer.show("active after stop") + + ". originalThreadCount=" + + originalThreadCount + + " threadCountAfterStop=" + + threadCountAfterStop, + threadCountAfterStop <= originalThreadCount); + } + + + /** + * Filters any daemon threads from the thread list. + * + * Thread counts before and after the test should ideally be equal. + * However there is no guarantee that the JVM does not create any + * additional threads itself. + * E.g. on Mac OSX there is a JVM internal thread called + * "Poller SunPKCS11-Darwin" created after the test go started and + * under the main thread group. + * When debugging tests in Eclipse another so called "Reader" thread + * is created by Eclipse. + * So we cannot assume that the JVM does not create additional threads + * during the test. However for the time being we assume that any such + * additionally created threads are daemon threads. + * + * @param threads - the array of threads to parse + * @return a new array with any daemon threads removed + */ + public Thread[] filterDaemonThreads(Thread[] threads) throws Exception { + + List threadList = new ArrayList(Arrays.asList(threads)); + + // Can't use an Iterator as it would raise a + // ConcurrentModificationException when trying to remove an element + // from the list, so using standard walk through + for (int i = 0 ; i < threadList.size(); i++) { + + Thread thread = threadList.get(i); + LOG.debug("Inspecting thread " + thread.getName()); + if (thread.isDaemon()) { + LOG.debug("Removing deamon thread."); + threadList.remove(thread); + Thread.sleep(100); + + } + } + LOG.debug("Converting list back to Array"); + return threadList.toArray(new Thread[0]); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/CompositeMessageCursorUsageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/CompositeMessageCursorUsageTest.java new file mode 100644 index 0000000000..d0d5965aed --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/CompositeMessageCursorUsageTest.java @@ -0,0 +1,90 @@ +/** + * 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.usage; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.ObjectName; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; + +public class CompositeMessageCursorUsageTest extends TestCase { + + BrokerService broker; + + public void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.start(); + } + + protected void tearDown() throws Exception { + broker.stop(); + } + + public void testCompositeMessageUsage() throws Exception { + + String compositeQueue = "compositeA,compositeB"; + + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost"); + JmsTemplate jt = new JmsTemplate(cf); + + jt.send(compositeQueue, new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + TextMessage tm = session.createTextMessage(); + tm.setText("test"); + return tm; + } + }); + + jt.send("noCompositeA", new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + TextMessage tm = session.createTextMessage(); + tm.setText("test"); + return tm; + } + }); + + jt.send("noCompositeB", new MessageCreator() { + public Message createMessage(Session session) throws JMSException { + TextMessage tm = session.createTextMessage(); + tm.setText("test"); + return tm; + } + }); + + assertEquals("Cursor memory usage wrong for 'noCompositeA' queue", 1032, getQueueView("noCompositeA").getCursorMemoryUsage()); + assertEquals("Cursor memory usage wrong for 'noCompositeB' queue", 1032, getQueueView("noCompositeB").getCursorMemoryUsage()); + assertEquals("Cursor memory usage wrong for 'CompositeA' queue", 1032, getQueueView("compositeA").getCursorMemoryUsage()); + assertEquals("Cursor memory usage wrong for 'CompositeB' queue", 1032, getQueueView("compositeB").getCursorMemoryUsage()); + + } + + public QueueViewMBean getQueueView(String queueName) throws Exception { + ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq" + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + queueName); + return (QueueViewMBean) broker.getManagementContext().newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/JobSchedulerStoreUsageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/JobSchedulerStoreUsageTest.java new file mode 100644 index 0000000000..f9697d975a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/JobSchedulerStoreUsageTest.java @@ -0,0 +1,107 @@ +/** + * 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.usage; + +import java.io.File; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.ScheduledMessage; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.IOHelper; +import org.apache.activemq.util.ProducerThread; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JobSchedulerStoreUsageTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(JobSchedulerStoreUsageTest.class); + + final int WAIT_TIME_MILLS = 20*1000; + + @Override + protected BrokerService createBroker() throws Exception { + File schedulerDirectory = new File("target/scheduler"); + + IOHelper.mkdirs(schedulerDirectory); + IOHelper.deleteChildren(schedulerDirectory); + + BrokerService broker = super.createBroker(); + broker.setSchedulerSupport(true); + broker.setSchedulerDirectoryFile(schedulerDirectory); + broker.getSystemUsage().getJobSchedulerUsage().setLimit(7 * 1024); + broker.deleteAllMessages(); + return broker; + } + + @Override + protected boolean isPersistent() { + return true; + } + + public void testJmx() throws Exception { + + LOG.info("Initial scheduler usage: {}", broker.getAdminView().getJobSchedulerStorePercentUsage()); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = sess.createQueue(this.getClass().getName()); + final ProducerThread producer = new ProducerThread(sess, dest) { + @Override + protected Message createMessage(int i) throws Exception { + Message message = super.createMessage(i); + message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, WAIT_TIME_MILLS / 2); + return message; + } + }; + producer.setMessageCount(100); + producer.start(); + + assertEquals(7 * 1024, broker.getAdminView().getJobSchedulerStoreLimit()); + + // wait for the producer to block + Thread.sleep(WAIT_TIME_MILLS / 2); + + assertTrue(broker.getAdminView().getJobSchedulerStorePercentUsage() > 100); + + broker.getAdminView().setJobSchedulerStoreLimit(1024 * 1024 * 33); + + Thread.sleep(WAIT_TIME_MILLS); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return producer.getSentCount() == producer.getMessageCount(); + } + }, WAIT_TIME_MILLS * 2); + + assertEquals("Producer didn't send all messages", producer.getMessageCount(), producer.getSentCount()); + + LOG.info("Final scheduler usage: {}", broker.getAdminView().getJobSchedulerStorePercentUsage()); + + assertTrue(broker.getAdminView().getJobSchedulerStorePercentUsage() < 100); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/StoreUsageLimitsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/StoreUsageLimitsTest.java new file mode 100644 index 0000000000..80bb0a389e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/StoreUsageLimitsTest.java @@ -0,0 +1,75 @@ +/** + * 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.usage; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; + +public class StoreUsageLimitsTest extends EmbeddedBrokerTestSupport { + + final int WAIT_TIME_MILLS = 20 * 1000; + private static final String limitsLogLevel = "warn"; + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.getSystemUsage().getMemoryUsage().setLimit(Long.MAX_VALUE); + broker.getSystemUsage().setCheckLimitsLogLevel(limitsLogLevel); + broker.deleteAllMessages(); + return broker; + } + + @Override + protected boolean isPersistent() { + return true; + } + + public void testCheckLimitsLogLevel() throws Exception { + + File file = new File("target/activemq-test.log"); + if (!file.exists()) { + fail("target/activemq-test.log was not created."); + } + + BufferedReader br = null; + boolean foundUsage = false; + + try { + br = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"))); + String line = null; + while ((line = br.readLine()) != null) { + if (line.contains(new String(Long.toString(Long.MAX_VALUE / (1024 * 1024)))) && line.contains(limitsLogLevel.toUpperCase())) { + foundUsage = true; + } + } + } catch (Exception e) { + fail(e.getMessage()); + } finally { + br.close(); + } + + if (!foundUsage) + fail("checkLimitsLogLevel message did not write to log target/activemq-test.log"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/StoreUsageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/StoreUsageTest.java new file mode 100644 index 0000000000..901a325b17 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usage/StoreUsageTest.java @@ -0,0 +1,71 @@ +/** + * 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.usage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.ProducerThread; +import org.apache.activemq.util.Wait; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Session; + +public class StoreUsageTest extends EmbeddedBrokerTestSupport { + + final int WAIT_TIME_MILLS = 20*1000; + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService broker = super.createBroker(); + broker.getSystemUsage().getStoreUsage().setLimit(10 * 1024); + broker.deleteAllMessages(); + return broker; + } + + protected boolean isPersistent() { + return true; + } + + public void testJmx() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection conn = factory.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = sess.createQueue(this.getClass().getName()); + final ProducerThread producer = new ProducerThread(sess, dest); + producer.start(); + + // wait for the producer to block + Thread.sleep(WAIT_TIME_MILLS / 2); + + broker.getAdminView().setStoreLimit(1024 * 1024); + + Thread.sleep(WAIT_TIME_MILLS); + + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return producer.getSentCount() == producer.getMessageCount(); + } + }, WAIT_TIME_MILLS * 2); + + assertEquals("Producer didn't send all messages", producer.getMessageCount(), producer.getSentCount()); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AMQ2927Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AMQ2927Test.java new file mode 100644 index 0000000000..e2df753ec5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AMQ2927Test.java @@ -0,0 +1,135 @@ +/** + * 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.usecases; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import javax.jms.MessageConsumer; +import java.net.URI; + + +public class AMQ2927Test extends JmsMultipleBrokersTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(AMQ2927Test.class); + + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + BrokerService brokerA = createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=true&useJmx=false&deleteAllMessagesOnStartup=true")); + brokerA.setBrokerId("BrokerA"); + BrokerService brokerB = createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB?persistent=true&useJmx=false&deleteAllMessagesOnStartup=true")); + brokerB.setBrokerId("BrokerB"); + NetworkConnector aTOb = bridgeBrokers(brokers.get("BrokerA").broker, brokers.get("BrokerB").broker, false, 2, true, true); + aTOb.addStaticallyIncludedDestination(queue); + NetworkConnector bTOa = bridgeBrokers(brokers.get("BrokerB").broker, brokers.get("BrokerA").broker, false, 2, true, true); + bTOa.addStaticallyIncludedDestination(queue); + + startAllBrokers(); + waitForBridgeFormation(); + + } + + public void testRestartSend() throws Exception { + + Thread.sleep(1000); + + LOG.info("restarting broker"); + + restartBroker("BrokerA"); + + Thread.sleep(5000); + + LOG.info("sending message"); + + sendMessages("BrokerA", queue, 1); + + Thread.sleep(3000); + + LOG.info("consuming message"); + + MessageConsumer consumerA = createConsumer("BrokerA", queue); + MessageConsumer consumerB = createConsumer("BrokerB", queue); + + Thread.sleep(1000); + + MessageIdList messagesA = getConsumerMessages("BrokerA", consumerA); + MessageIdList messagesB = getConsumerMessages("BrokerB", consumerB); + + LOG.info("consumerA = " + messagesA); + LOG.info("consumerB = " + messagesB); + + messagesA.assertMessagesReceived(0); + messagesB.assertMessagesReceived(1); + + } + + + public void testSendRestart() throws Exception { + + Thread.sleep(1000); + + LOG.info("sending message"); + + sendMessages("BrokerA", queue, 1); + + Thread.sleep(3000); + + LOG.info("restarting broker"); + + restartBroker("BrokerA"); + + Thread.sleep(5000); + + LOG.info("consuming message"); + + MessageConsumer consumerA = createConsumer("BrokerA", queue); + MessageConsumer consumerB = createConsumer("BrokerB", queue); + + Thread.sleep(1000); + + MessageIdList messagesA = getConsumerMessages("BrokerA", consumerA); + MessageIdList messagesB = getConsumerMessages("BrokerB", consumerB); + + LOG.info("consumerA = " + messagesA); + LOG.info("consumerB = " + messagesB); + + messagesA.assertMessagesReceived(0); + messagesB.assertMessagesReceived(1); + } + + protected void restartBroker(String brokerName) throws Exception { + destroyBroker("BrokerA"); + BrokerService broker = createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=true&useJmx=false")); + broker.setBrokerId("BrokerA"); + NetworkConnector aTOb = bridgeBrokers(brokers.get("BrokerA").broker, brokers.get("BrokerB").broker, false, 2, true, true); + aTOb.addStaticallyIncludedDestination(queue); + broker.start(); + broker.waitUntilStarted(); + waitForBridgeFormation(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AMQStackOverFlowTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AMQStackOverFlowTest.java new file mode 100644 index 0000000000..3803723f2a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AMQStackOverFlowTest.java @@ -0,0 +1,148 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.Session; +import javax.jms.TextMessage; + +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.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.usage.SystemUsage; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.core.MessageCreator; + +public class AMQStackOverFlowTest extends TestCase { + + private static final String URL1 = "tcp://localhost:61616"; + + private static final String URL2 = "tcp://localhost:61617"; + + public void testStackOverflow() throws Exception { + BrokerService brokerService1 = null; + BrokerService brokerService2 = null; + + try { + brokerService1 = createBrokerService("broker1", URL1, URL2); + brokerService1.start(); + brokerService2 = createBrokerService("broker2", URL2, URL1); + brokerService2.start(); + + final ActiveMQConnectionFactory cf1 = new ActiveMQConnectionFactory(URL1); + cf1.setUseAsyncSend(false); + + final ActiveMQConnectionFactory cf2 = new ActiveMQConnectionFactory(URL2); + cf2.setUseAsyncSend(false); + + final JmsTemplate template1 = new JmsTemplate(cf1); + template1.setReceiveTimeout(10000); + + template1.send("test.q", new MessageCreator() { + + @Override + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("test"); + } + + }); + + final JmsTemplate template2 = new JmsTemplate(cf2); + template2.setReceiveTimeout(10000); + + final Message m = template2.receive("test.q"); + assertTrue(m instanceof TextMessage); + + final TextMessage tm = (TextMessage)m; + + assertEquals("test", tm.getText()); + + template2.send("test2.q", new MessageCreator() { + + @Override + public Message createMessage(Session session) throws JMSException { + return session.createTextMessage("test2"); + } + }); + + final Message m2 = template1.receive("test2.q"); + assertNotNull(m2); + assertTrue(m2 instanceof TextMessage); + + final TextMessage tm2 = (TextMessage)m2; + + assertEquals("test2", tm2.getText()); + + } finally { + brokerService1.stop(); + brokerService1 = null; + brokerService2.stop(); + brokerService2 = null; + } + } + + private BrokerService createBrokerService(final String brokerName, final String uri1, final String uri2) + throws Exception { + final BrokerService brokerService = new BrokerService(); + + brokerService.setBrokerName(brokerName); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + + final SystemUsage memoryManager = new SystemUsage(); + //memoryManager.getMemoryUsage().setLimit(10); + brokerService.setSystemUsage(memoryManager); + + final List policyEntries = new ArrayList(); + + final PolicyEntry entry = new PolicyEntry(); + entry.setQueue(">"); + //entry.setMemoryLimit(1); + policyEntries.add(entry); + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + brokerService.setDestinationPolicy(policyMap); + + final TransportConnector tConnector = new TransportConnector(); + tConnector.setUri(new URI(uri1)); + tConnector.setName(brokerName + ".transportConnector"); + brokerService.addConnector(tConnector); + + if (uri2 != null) { + final NetworkConnector nc = new DiscoveryNetworkConnector(new URI("static:" + uri2)); + nc.setBridgeTempDestinations(true); + nc.setBrokerName(brokerName); + //nc.setPrefetchSize(1); + brokerService.addNetworkConnector(nc); + } + + return brokerService; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AbstractTwoBrokerNetworkConnectorWildcardIncludedDestinationTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AbstractTwoBrokerNetworkConnectorWildcardIncludedDestinationTestSupport.java new file mode 100644 index 0000000000..7ccf5d10a3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AbstractTwoBrokerNetworkConnectorWildcardIncludedDestinationTestSupport.java @@ -0,0 +1,147 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.IOException; +import java.net.URI; + +import javax.jms.MessageConsumer; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.MessageIdList; + +public abstract class AbstractTwoBrokerNetworkConnectorWildcardIncludedDestinationTestSupport extends JmsMultipleBrokersTestSupport { + + protected static final int MESSAGE_COUNT = 1; + boolean dynamicOnly = true; + int networkTTL = 1; + boolean conduit = true; + boolean suppressDuplicateQueueSubscriptions = true; + boolean decreaseNetworkConsumerPriority = true; + + /** + * simple nwob + */ + public void testSimpleNWOB() throws Exception { + + sendReceive("BrokerA", "local.test", false, "BrokerB", "local.test", false, 1, 0); + sendReceive("BrokerA", "local.test", true, "BrokerB", "local.test", true, 1, 0); + sendReceive("BrokerA", "global.test", false, "BrokerB", "global.test", false, 1, 1); + sendReceive("BrokerA", "global.test", true, "BrokerB", "global.test", true, 1, 1); + + } + + /** + * nwob with wild-card subscriptions + */ + public void testSimpleNWOBWithWildcardSubscriptions() throws Exception { + + sendReceive("BrokerA", "local.test.1", false, "BrokerB", "local.test.>", false, 1, 0); + sendReceive("BrokerA", "local.test.2", true, "BrokerB", "local.test.>", true, 1, 0); + sendReceive("BrokerA", "global.test.1", false, "BrokerB", "global.test.>", false, 1, 1); + sendReceive("BrokerA", "global.test.2", true, "BrokerB", "global.test.>", true, 1, 1); + + } + + /** + * nwob with virtual destinations + */ + public void testSimpleNWOBWithVirtualDestinations() throws Exception { + + sendReceive("BrokerA", "local.test", true, "BrokerB", "Consumer.a.local.test", false, 1, 0); + sendReceive("BrokerA", "global.test", true, "BrokerB", "Consumer.a.global.test", false, 1, 1); + + } + + /** + * nwob with virtual destinations and wild-card subscriptions + */ + public void testSimpleNWOBWithVirtualDestinationsAndWildcardSubscriptions() throws Exception { + + sendReceive("BrokerA", "local.test.1", true, "BrokerB", "Consumer.a.local.test.>", false, 1, 0); + sendReceive("BrokerA", "global.test.1", true, "BrokerB", "Consumer.a.global.test.>", false, 1, 1); + + } + + public void sendReceive(String broker1, String dest1, boolean topic1, String broker2, String dest2, boolean topic2, int send, int expected) throws Exception{ + MessageConsumer client = createConsumer(broker2, createDestination(dest2, topic2)); + Thread.sleep(2000); + sendMessages(broker1, createDestination(dest1, topic1), send); + MessageIdList msgs = getConsumerMessages(broker2, client); + msgs.setMaximumDuration(10000); + msgs.waitForMessagesToArrive(send); + assertEquals(expected, msgs.getMessageCount()); + client.close(); + Thread.sleep(1000); + } + + protected abstract void addIncludedDestination(NetworkConnector networkConnector); + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + String options = new String("?useJmx=false&deleteAllMessagesOnStartup=true"); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61616)/BrokerA" + options)); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61617)/BrokerB" + options)); + + // Setup broker networks + NetworkConnector nc = bridgeBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduit); + nc.setDecreaseNetworkConsumerPriority(decreaseNetworkConsumerPriority); + nc.setSuppressDuplicateQueueSubscriptions(suppressDuplicateQueueSubscriptions); + + addIncludedDestination(nc); + + nc = bridgeBrokers("BrokerB", "BrokerA", dynamicOnly, networkTTL, conduit); + nc.setDecreaseNetworkConsumerPriority(decreaseNetworkConsumerPriority); + nc.setSuppressDuplicateQueueSubscriptions(suppressDuplicateQueueSubscriptions); + + addIncludedDestination(nc); + + startAllBrokers(); + + } + + private BrokerService createAndConfigureBroker(URI uri) throws Exception { + BrokerService broker = createBroker(uri); + + configurePersistenceAdapter(broker); + + // make all topics virtual and consumers use the default prefix + VirtualDestinationInterceptor virtualDestinationInterceptor = new VirtualDestinationInterceptor(); + virtualDestinationInterceptor.setVirtualDestinations(new VirtualDestination[]{new VirtualTopic()}); + DestinationInterceptor[] destinationInterceptors = new DestinationInterceptor[]{virtualDestinationInterceptor}; + broker.setDestinationInterceptors(destinationInterceptors); + return broker; + } + + protected void configurePersistenceAdapter(BrokerService broker) throws IOException { + File dataFileDir = new File("target/test-amq-data/kahadb/" + broker.getBrokerName()); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(dataFileDir); + broker.setPersistenceAdapter(kaha); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AdvisoryTopicCleanUpTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AdvisoryTopicCleanUpTest.java new file mode 100644 index 0000000000..2d279636be --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AdvisoryTopicCleanUpTest.java @@ -0,0 +1,162 @@ +/** + * 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.usecases; + +import static org.junit.Assert.*; + +import java.util.concurrent.TimeUnit; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; + +public class AdvisoryTopicCleanUpTest { + + private static final Logger LOG = LoggerFactory.getLogger(AdvisoryTopicCleanUpTest.class); + + private BrokerService broker; + private String connectionUri; + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(connectionUri + "?jms.redeliveryPolicy.maximumRedeliveries=2"); + } + + @Before + public void setUp() throws Exception { + createBroker(); + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + private void createBroker() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.setUseJmx(true); + connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString(); + + PolicyEntry policy = new PolicyEntry(); + policy.setAdvisoryForFastProducers(true); + policy.setAdvisoryForConsumed(true); + policy.setAdvisoryForDelivery(true); + policy.setAdvisoryForDiscardingMessages(true); + policy.setAdvisoryForSlowConsumers(true); + policy.setAdvisoryWhenFull(true); + policy.setProducerFlowControl(false); + PolicyMap pMap = new PolicyMap(); + pMap.setDefaultEntry(policy); + broker.setDestinationPolicy(pMap); + + broker.start(); + } + + protected Connection createConnection() throws Exception { + Connection con = createConnectionFactory().createConnection(); + con.start(); + return con; + } + + private void destroyBroker() throws Exception { + if (broker != null) + broker.stop(); + } + + @Test + public void testAdvisoryTopic() throws Exception { + Connection connection = createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQDestination queue = (ActiveMQDestination) session.createQueue("AdvisoryTopicCleanUpTestQueue"); + MessageProducer prod = session.createProducer(queue); + Message message = session.createMessage(); + prod.send(message); + message = session.createMessage(); + prod.send(message); + message = session.createMessage(); + prod.send(message, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, 1000); + connection.close(); + connection = createConnection(); + + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + message = consumer.receive(60 * 1000); + message.acknowledge(); + connection.close(); + connection = null; + + for (int i = 0; i < 2; i++) { + connection = createConnection(); + session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + consumer = session.createConsumer(queue); + message = consumer.receive(60 * 1000); + session.rollback(); + connection.close(); + connection = null; + } + + Thread.sleep(2 * 1000); + + connection = createConnection(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + consumer = session.createConsumer(queue); + message = consumer.receive(1000); + if (message != null) + message.acknowledge(); + connection.close(); + connection = null; + + TimeUnit.SECONDS.sleep(1); + + ActiveMQDestination dests[] = broker.getRegionBroker().getDestinations(); + + for (ActiveMQDestination destination: dests) { + String name = destination.getPhysicalName(); + if (name.contains(queue.getPhysicalName())) { + LOG.info("Destination on Broker before removing the Queue: " + name); + } + } + + dests = broker.getRegionBroker().getDestinations(); + if (dests == null) { + fail("Should have Destination for: " + queue.getPhysicalName()); + } + + broker.getAdminView().removeQueue(queue.getPhysicalName()); + + dests = broker.getRegionBroker().getDestinations(); + if (dests != null) + { + for (ActiveMQDestination destination: dests) { + String name = destination.getPhysicalName(); + LOG.info("Destination on broker after removing the Queue: " + name); + assertFalse("Advisory topic should not exist. " + name, + name.startsWith("ActiveMQ.Advisory") && name.contains(queue.getPhysicalName())); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AdvisoryTopicDeletionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AdvisoryTopicDeletionTest.java new file mode 100644 index 0000000000..d84ad1871e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AdvisoryTopicDeletionTest.java @@ -0,0 +1,125 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AdvisoryTopicDeletionTest extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(AdvisoryTopicDeletionTest.class); + + private BrokerService broker; + private Connection connection; + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://" + getName()); + } + + @Override + protected void setUp() throws Exception { + createBroker(); + topic = false; + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + private void createBroker() throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://localhost)"); + broker.setPersistent(false); + broker.setBrokerName(getName()); + broker.start(); + + connection = createConnection(); + } + + @Override + protected Connection createConnection() throws Exception { + Connection con = super.createConnection(); + con.start(); + return con; + } + + private void destroyBroker() throws Exception { + if (connection != null) + connection.close(); + if (broker != null) + broker.stop(); + } + + public void doTest() throws Exception { + Destination dest = createDestination(); + + Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = consumerSession.createConsumer(dest); + + MessageProducer prod = producerSession.createProducer(dest); + Message message = producerSession.createMessage(); + prod.send(message); + + consumer.receive(60 * 1000); + connection.close(); + connection = null; + + if ( topic ) { + broker.getAdminView().removeTopic(((ActiveMQDestination)dest).getPhysicalName()); + } else { + broker.getAdminView().removeQueue(((ActiveMQDestination)dest).getPhysicalName()); + } + + ActiveMQDestination dests[] = broker.getRegionBroker().getDestinations(); + int matchingDestinations = 0; + for (ActiveMQDestination destination: dests) { + String name = destination.getPhysicalName(); + LOG.debug("Found destination " + name); + if (name.startsWith("ActiveMQ.Advisory") && name.contains(getDestinationString())) { + matchingDestinations++; + } + } + + assertEquals("No matching destinations should be found", 0, matchingDestinations); + } + + public void testTopic() throws Exception { + topic=true; + doTest(); + } + + public void testQueue() throws Exception { + topic=false; + doTest(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AuthorizationFromAdminViewTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AuthorizationFromAdminViewTest.java new file mode 100644 index 0000000000..33651cb03c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/AuthorizationFromAdminViewTest.java @@ -0,0 +1,65 @@ +/** + * 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.usecases; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.security.AuthorizationPlugin; +import org.apache.activemq.security.SimpleAuthorizationMap; + +public class AuthorizationFromAdminViewTest extends org.apache.activemq.TestSupport { + + private BrokerService broker; + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://" + getName()); + } + + protected void setUp() throws Exception { + createBroker(); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + private void createBroker() throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://localhost)"); + broker.setPersistent(false); + broker.setBrokerName(getName()); + + AuthorizationPlugin plugin = new AuthorizationPlugin(); + plugin.setMap(new SimpleAuthorizationMap()); + BrokerPlugin[] plugins = new BrokerPlugin[] {plugin}; + broker.setPlugins(plugins); + + broker.start(); + } + + private void destroyBroker() throws Exception { + if (broker != null) + broker.stop(); + } + + public void testAuthorizationFromAdminView() throws Exception { + broker.getAdminView().addQueue(getDestinationString()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BacklogNetworkCrossTalkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BacklogNetworkCrossTalkTest.java new file mode 100644 index 0000000000..3e9b91362a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BacklogNetworkCrossTalkTest.java @@ -0,0 +1,96 @@ +/** + * 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.usecases; + +import java.net.URI; +import javax.jms.MessageConsumer; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BacklogNetworkCrossTalkTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(BacklogNetworkCrossTalkTest.class); + + protected BrokerService createBroker(String brokerName) throws Exception { + BrokerService broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(true); + broker.setUseJmx(false); + broker.setBrokerName(brokerName); + broker.addConnector(new URI(AUTO_ASSIGN_TRANSPORT)); + brokers.put(brokerName, new BrokerItem(broker)); + + return broker; + } + + public void testProduceConsume() throws Exception { + createBroker("A"); + createBroker("B"); + + NetworkConnector nc = bridgeBrokers("A", "B"); + nc.setDuplex(true); + nc.setDispatchAsync(false); + startAllBrokers(); + + waitForBridgeFormation(); + + final int numMessages = 10000; + // Create queue + ActiveMQDestination destA = createDestination("AAA", false); + sendMessages("A", destA, numMessages); + + ActiveMQDestination destB = createDestination("BBB", false); + sendMessages("B", destB, numMessages); + + // consume across network + LOG.info("starting consumers.."); + + // Setup consumers + MessageConsumer clientA = createConsumer("A", destB); + // Setup consumers + MessageConsumer clientB = createConsumer("B", destA); + + + final long maxWait = 5 * 60 * 1000l; + MessageIdList listA = getConsumerMessages("A", clientA); + listA.setMaximumDuration(maxWait); + listA.waitForMessagesToArrive(numMessages); + + MessageIdList listB = getConsumerMessages("B", clientB); + listB.setMaximumDuration(maxWait); + listB.waitForMessagesToArrive(numMessages); + + assertEquals("got all on A" + listA.getMessageCount(), + numMessages, listA.getMessageCount()); + + assertEquals("got all on B" + listB.getMessageCount(), + numMessages, listB.getMessageCount()); + + } + + @Override + public void setUp() throws Exception { + messageSize = 5000; + super.setMaxTestTime(10*60*1000); + super.setAutoFail(true); + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BatchedMessagePriorityConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BatchedMessagePriorityConsumerTest.java new file mode 100644 index 0000000000..16e2ac2530 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BatchedMessagePriorityConsumerTest.java @@ -0,0 +1,81 @@ +/** + * 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.usecases; + +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BatchedMessagePriorityConsumerTest extends JmsTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(BatchedMessagePriorityConsumerTest.class); + + public void testBatchWithLowPriorityFirstAndClientSupport() throws Exception { + doTestBatchWithLowPriorityFirst(true); + } + + public void testBatchWithLowPriorityFirstAndClientSupportOff() throws Exception { + doTestBatchWithLowPriorityFirst(false); + } + + public void doTestBatchWithLowPriorityFirst(boolean clientPrioritySupport) throws Exception { + + connection.start(); + connection.setMessagePrioritySupported(clientPrioritySupport); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQDestination destination = createDestination(session, ActiveMQDestination.QUEUE_TYPE); + + + MessageProducer producer = session.createProducer(destination); + producer.setPriority(0); + sendMessages(session, producer, 2); + producer.close(); + + MessageProducer producer2 = session.createProducer(destination); + producer2.setPriority(9); + sendMessages(session, producer2, 3); + producer2.close(); + + session.close(); + + Session consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer messageConsumer = consumerSession.createConsumer(destination); + + for (int i = 0; i < 5; i++) { + Message message = messageConsumer.receive(4000); + LOG.info("MessageID: " + message.getJMSMessageID()); + } + + consumerSession.commit(); + consumerSession.close(); + + // should be nothing left + consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + messageConsumer = consumerSession.createConsumer(destination); + + assertNull("No message left", messageConsumer.receive(1000)); + + consumerSession.close(); + + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrokerQueueNetworkWithDisconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrokerQueueNetworkWithDisconnectTest.java new file mode 100644 index 0000000000..0b8de2905a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrokerQueueNetworkWithDisconnectTest.java @@ -0,0 +1,259 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.TextMessage; + +import junit.framework.Test; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.transport.vm.VMTransportFactory; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.SocketProxy; +import org.apache.activemq.util.Wait; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +public class BrokerQueueNetworkWithDisconnectTest extends JmsMultipleBrokersTestSupport { + private static final Log LOG = LogFactory.getLog(BrokerQueueNetworkWithDisconnectTest.class); + private static final int NETWORK_DOWN_TIME = 5000; + protected static final int MESSAGE_COUNT = 200; + private static final String HUB = "HubBroker"; + private static final String SPOKE = "SpokeBroker"; + private SocketProxy socketProxy; + private long networkDownTimeStart; + public boolean useDuplexNetworkBridge = true; + public boolean simulateStalledNetwork; + private long inactiveDuration = 1000; + private boolean useSocketProxy = true; + + public void initCombosForTestSendOnAReceiveOnBWithTransportDisconnect() { + addCombinationValues( "useDuplexNetworkBridge", new Object[]{ Boolean.TRUE, Boolean.FALSE} ); + addCombinationValues( "simulateStalledNetwork", new Object[]{ Boolean.TRUE } ); + } + + public void testSendOnAReceiveOnBWithTransportDisconnect() throws Exception { + bridgeBrokers(SPOKE, HUB); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer client = createConsumer(HUB, dest); + + // allow subscription information to flow back to Spoke + sleep(600); + + // Send messages + sendMessages(SPOKE, dest, MESSAGE_COUNT); + + MessageIdList msgs = getConsumerMessages(HUB, client); + msgs.waitForMessagesToArrive(MESSAGE_COUNT); + + assertTrue("At least message " + MESSAGE_COUNT + + " must be recieved, duplicates are expected, count=" + msgs.getMessageCount(), + MESSAGE_COUNT <= msgs.getMessageCount()); + } + + @SuppressWarnings("unchecked") + public void testNoStuckConnectionsWithTransportDisconnect() throws Exception { + inactiveDuration=60000l; + useDuplexNetworkBridge = true; + + bridgeBrokers(SPOKE, HUB); + + final BrokerItem hub = brokers.get(HUB); + hub.broker.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + int sleepCount = 2; + @Override + public void removeConnection(ConnectionContext context, + ConnectionInfo info, Throwable error) + throws Exception { + try { + while(--sleepCount >= 0) { + LOG.info("sleeping for a bit in close impl to simulate load where reconnect fails due to a pending close"); + TimeUnit.SECONDS.sleep(2); + } + } catch (Exception ignored) {} + super.removeConnection(context, info, error); + } + } + }); + startAllBrokers(); + waitForBridgeFormation(); + + // kill the initiator side, leaving remote end intact + // simulate async network breakage + // remote side will need to spot duplicate network and stop/kill the original + for (int i=0; i< 3; i++) { + socketProxy.halfClose(); + sleep(10000); + } + // wait for full reformation of bridge + // verify no extra connections + boolean allGood = Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + long numConnections = hub.broker.getTransportConnectors().get(0).getConnections().size(); + LOG.info("Num connetions:" + numConnections); + return numConnections == 1; + }}); + if (!allGood) { + dumpAllThreads("ExtraHubConnection"); + } + assertTrue("should be only one transport connection for the single duplex network connector", allGood); + + allGood = Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + long numVmConnections = VMTransportFactory.SERVERS.get(HUB).getConnectionCount(); + LOG.info("Num VM connetions:" + numVmConnections); + return numVmConnections == 2; + }}); + if (!allGood) { + dumpAllThreads("ExtraHubVMConnection"); + } + assertTrue("should be only 2 vm connections for the single network duplex network connector", allGood); + } + + public void testTwoDuplexNCsAreAllowed() throws Exception { + useDuplexNetworkBridge = true; + useSocketProxy = false; + + NetworkConnector connector = bridgeBrokers(SPOKE, HUB); + connector.setName("FirstDuplex"); + connector = bridgeBrokers(SPOKE, HUB); + connector.setName("SecondDuplex"); + + startAllBrokers(); + waitForBridgeFormation(); + + BrokerItem hub = brokers.get(HUB); + assertEquals("Has two transport Connectors", 2, hub.broker.getTransportConnectors().get(0).getConnections().size()); + } + + @Override + protected void startAllBrokers() throws Exception { + // Ensure HUB is started first so bridge will be active from the get go + BrokerItem brokerItem = brokers.get(HUB); + brokerItem.broker.start(); + brokerItem = brokers.get(SPOKE); + brokerItem.broker.start(); + sleep(600); + } + + @Override + public void setUp() throws Exception { + networkDownTimeStart = 0; + inactiveDuration = 1000; + useSocketProxy = true; + super.setAutoFail(true); + super.setUp(); + final String options = "?persistent=true&useJmx=false&deleteAllMessagesOnStartup=true"; + createBroker(new URI("broker:(tcp://localhost:61617)/" + HUB + options)); + createBroker(new URI("broker:(tcp://localhost:61616)/" + SPOKE + options)); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + if (socketProxy != null) { + socketProxy.close(); + } + } + + public static Test suite() { + return suite(BrokerQueueNetworkWithDisconnectTest.class); + } + + @Override + protected void onSend(int i, TextMessage msg) { + sleep(50); + if (i == 50 || i == 150) { + if (simulateStalledNetwork) { + socketProxy.pause(); + } else { + socketProxy.close(); + } + networkDownTimeStart = System.currentTimeMillis(); + } else if (networkDownTimeStart > 0) { + // restart after NETWORK_DOWN_TIME seconds + if (networkDownTimeStart + NETWORK_DOWN_TIME < System.currentTimeMillis()) { + if (simulateStalledNetwork) { + socketProxy.goOn(); + } else { + socketProxy.reopen(); + } + networkDownTimeStart = 0; + } else { + // slow message production to allow bridge to recover and limit message duplication + sleep(500); + } + } + super.onSend(i, msg); + } + + private void sleep(int milliSecondTime) { + try { + Thread.sleep(milliSecondTime); + } catch (InterruptedException igonred) { + } + } + + @Override + protected NetworkConnector bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker, boolean dynamicOnly, int networkTTL, boolean conduit, boolean failover) throws Exception { + List transportConnectors = remoteBroker.getTransportConnectors(); + URI remoteURI; + if (!transportConnectors.isEmpty()) { + remoteURI = transportConnectors.get(0).getConnectUri(); + if (useSocketProxy) { + socketProxy = new SocketProxy(remoteURI); + remoteURI = socketProxy.getUrl(); + } + DiscoveryNetworkConnector connector = new DiscoveryNetworkConnector(new URI("static:(" + remoteURI + + "?wireFormat.maxInactivityDuration=" + inactiveDuration + "&wireFormat.maxInactivityDurationInitalDelay=" + inactiveDuration + ")?useExponentialBackOff=false")); + connector.setDynamicOnly(dynamicOnly); + connector.setNetworkTTL(networkTTL); + localBroker.addNetworkConnector(connector); + maxSetupTime = 2000; + if (useDuplexNetworkBridge) { + connector.setDuplex(true); + } + return connector; + } else { + throw new Exception("Remote broker has no registered connectors."); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrowseDLQTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrowseDLQTest.java new file mode 100644 index 0000000000..bbcda6890d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrowseDLQTest.java @@ -0,0 +1,108 @@ +/** + * 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.usecases; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Test; + +import javax.jms.*; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.TabularData; + +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; + +/** + * @author Christian Posta + */ +public class BrowseDLQTest { + + private static final int NUM_MESSAGES = 100; + private BrokerService brokerService; + private ActiveMQQueue testQueue = new ActiveMQQueue("TEST.FOO"); + private ActiveMQQueue dlq = new ActiveMQQueue("ActiveMQ.DLQ"); + + @Test + public void testCannotBrowseDLQAsTable() throws Exception { + startBroker(); + // send 100 messages to queue with TTL of 1 second + sendMessagesToBeExpired(); + + // let's let the messages expire + TimeUnit.SECONDS.sleep(2); + + assertCanBrowse(); + } + + private void assertCanBrowse() throws MalformedObjectNameException, OpenDataException { + ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=ActiveMQ.DLQ"); + QueueViewMBean queue = (QueueViewMBean) + brokerService.getManagementContext().newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true); + // make sure we have messages here + assertTrue(queue.getQueueSize() > 0); + + CompositeData[] regularBrowse = queue.browse(); + assertNotNull(regularBrowse); + + TabularData tableData = queue.browseAsTable(); + assertNotNull(tableData); + + } + + + + @After + public void tearDown() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + private void startBroker() throws Exception { + brokerService = BrokerFactory.createBroker("broker:()/localhost?deleteAllMessagesOnStartup=true"); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setExpireMessagesPeriod(1000); + policyMap.setDefaultEntry(policyEntry); + brokerService.setDestinationPolicy(policyMap); + brokerService.start(); + brokerService.waitUntilStarted(); + } + + private void sendMessagesToBeExpired() throws JMSException, InterruptedException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(testQueue); + for (int i = 0; i < NUM_MESSAGES; i++) { + producer.send(testQueue,session.createTextMessage("Hello world #" + i), DeliveryMode.PERSISTENT, + 4, 500); + } + connection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrowseOverNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrowseOverNetworkTest.java new file mode 100644 index 0000000000..694facfb65 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/BrowseOverNetworkTest.java @@ -0,0 +1,250 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Arrays; +import java.util.Enumeration; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.QueueBrowser; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.QueueSubscription; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +public class BrowseOverNetworkTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(QueueSubscription.class); + protected static final int MESSAGE_COUNT = 10; + + public void testBrowse() throws Exception { + createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB?persistent=false&useJmx=false")); + createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=false&useJmx=false")); + + bridgeBrokers("BrokerA", "BrokerB"); + + + startAllBrokers(); + + Destination dest = createDestination("TEST.FOO", false); + + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + Thread.sleep(1000); + + int browsed = browseMessages("BrokerB", dest); + + Thread.sleep(1000); + + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + msgsA.waitForMessagesToArrive(MESSAGE_COUNT); + + Thread.sleep(1000); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT); + + LOG.info("A+B: " + msgsA.getMessageCount() + "+" + + msgsB.getMessageCount()); + assertEquals("Consumer on Broker A, should've consumed all messages", MESSAGE_COUNT, msgsA.getMessageCount()); + assertEquals("Broker B shouldn't get any messages", 0, browsed); + } + + public void testConsumerInfo() throws Exception { + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker1.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker2.xml")); + + startAllBrokers(); + + brokers.get("broker1").broker.waitUntilStarted(); + + + Destination dest = createDestination("QUEUE.A,QUEUE.B", false); + + + int broker1 = browseMessages("broker1", dest); + assertEquals("Browsed a message on an empty queue", 0, broker1); + Thread.sleep(1000); + int broker2 = browseMessages("broker2", dest); + assertEquals("Browsed a message on an empty queue", 0, broker2); + + } + + public class Browser extends Thread { + + String broker; + Destination dest; + int totalCount; + final int expect; + QueueBrowser browser = null; + MessageConsumer consumer = null; + boolean consume = false; + + public Browser(String broker, Destination dest, int expect) { + this.broker = broker; + this.dest = dest; + this.expect = expect; + } + + @Override + public void run() { + int retries = 0; + while (retries++ < 20 && totalCount != expect) { + try { + QueueBrowser browser = createBrowser(broker, dest); + int count = browseMessages(browser, broker); + if (consume) { + if (count != 0) { + MessageConsumer consumer = createSyncConsumer(broker, dest); + totalCount += count; + for (int i = 0; i < count; i++) { + ActiveMQTextMessage message = (ActiveMQTextMessage)consumer.receive(1000); + if (message == null) break; + LOG.info(broker + " consumer: " + message.getText() + " " + message.getDestination() + " " + message.getMessageId() + " " + Arrays.toString(message.getBrokerPath())); + } + } + } else { + totalCount = count; + } + LOG.info("browser '" + broker + "' browsed " + totalCount); + + Thread.sleep(1000); + } catch (Exception e) { + LOG.info("Exception browsing " + e, e); + } finally { + try { + if (browser != null) { + browser.close(); + } + if (consumer != null) { + consumer.close(); + } + } catch (Exception e) { + LOG.info("Exception closing browser " + e, e); + } + } + } + } + + public int getTotalCount() { + return totalCount; + } + } + + protected NetworkConnector bridgeBrokersWithIncludedDestination(String localBrokerName, String remoteBrokerName, ActiveMQDestination included, ActiveMQDestination excluded) throws Exception { + NetworkConnector nc = bridgeBrokers(localBrokerName, remoteBrokerName, false, 4, true); + nc.addStaticallyIncludedDestination(included); + if (excluded != null) { + nc.addExcludedDestination(excluded); + } + nc.setPrefetchSize(1); + return nc; + } + + public void testAMQ3020() throws Exception { + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker1A.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker1B.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker2A.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker2B.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker3A.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/browse-broker3B.xml")); + + brokers.get("broker-1A").broker.waitUntilStarted(); + brokers.get("broker-2A").broker.waitUntilStarted(); + brokers.get("broker-3A").broker.waitUntilStarted(); + + for (BrokerItem brokerItem : brokers.values()) { + final BrokerService broker = brokerItem.broker; + waitForBridgeFormation(broker, 1, 0); + waitForBridgeFormation(broker, 1, 1); + waitForBridgeFormation(broker, 1, 2); + waitForBridgeFormation(broker, 1, 3); + waitForBridgeFormation(broker, 1, 4); + } + + Destination composite = createDestination("PROD.FUSESOURCE.3.A,PROD.FUSESOURCE.3.B", false); + + final Browser browser1 = new Browser("broker-3A", composite, MESSAGE_COUNT); + browser1.start(); + + final Browser browser2 = new Browser("broker-3B", composite, MESSAGE_COUNT); + browser2.start(); + + LOG.info("Sending messages to broker-1A"); + sendMessages("broker-1A", composite, MESSAGE_COUNT); + LOG.info("Message sent to broker-1A"); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return browser1.getTotalCount() == MESSAGE_COUNT; + } + }); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return browser2.getTotalCount() == MESSAGE_COUNT; + } + }); + + browser1.join(); + browser2.join(); + + + LOG.info("broker-3A browsed " + browser1.getTotalCount()); + LOG.info("broker-3B browsed " + browser2.getTotalCount()); + + assertEquals(MESSAGE_COUNT * 2, browser1.getTotalCount() + browser2.getTotalCount() ); + + } + + protected int browseMessages(QueueBrowser browser, String name) throws Exception { + Enumeration msgs = browser.getEnumeration(); + int browsedMessage = 0; + while (msgs.hasMoreElements()) { + browsedMessage++; + ActiveMQTextMessage message = (ActiveMQTextMessage)msgs.nextElement(); + LOG.info(name + " browsed: " + message.getText() + " " + message.getDestination() + " " + message.getMessageId() + " " + Arrays.toString(message.getBrokerPath())); + } + return browsedMessage; + } + + + protected int browseMessages(String broker, Destination dest) throws Exception { + QueueBrowser browser = createBrowser(broker, dest); + int browsedMessage = browseMessages(browser, "browser"); + browser.close(); + return browsedMessage; + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ChangeSentMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ChangeSentMessageTest.java new file mode 100644 index 0000000000..90dfa2d4f1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ChangeSentMessageTest.java @@ -0,0 +1,67 @@ +/** + * 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.usecases; + +import java.util.HashMap; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Session; + +import org.apache.activemq.test.TestSupport; + +/** + * + */ +public class ChangeSentMessageTest extends TestSupport { + private static final int COUNT = 200; + private static final String VALUE_NAME = "value"; + + /** + * test Object messages can be changed after sending with no side-affects + * + * @throws Exception + */ + @SuppressWarnings("rawtypes") + public void testDoChangeSentMessage() throws Exception { + Destination destination = createDestination("test-" + ChangeSentMessageTest.class.getName()); + Connection connection = createConnection(); + connection.start(); + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(destination); + Session publisherSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = publisherSession.createProducer(destination); + HashMap map = new HashMap(); + ObjectMessage message = publisherSession.createObjectMessage(); + for (int i = 0; i < COUNT; i++) { + map.put(VALUE_NAME, Integer.valueOf(i)); + message.setObject(map); + producer.send(message); + assertTrue(message.getObject() == map); + } + for (int i = 0; i < COUNT; i++) { + ObjectMessage msg = (ObjectMessage)consumer.receive(); + HashMap receivedMap = (HashMap)msg.getObject(); + Integer intValue = (Integer)receivedMap.get(VALUE_NAME); + assertTrue(intValue.intValue() == i); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ChangeSessionDeliveryModeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ChangeSessionDeliveryModeTest.java new file mode 100644 index 0000000000..bb62d1a641 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ChangeSessionDeliveryModeTest.java @@ -0,0 +1,63 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.IllegalStateException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.apache.activemq.test.TestSupport; + +/** + * + */ +public class ChangeSessionDeliveryModeTest extends TestSupport implements MessageListener { + + /** + * test following condition- which are defined by JMS Spec 1.1: + * MessageConsumers cannot use a MessageListener and receive() from the same + * session + * + * @throws Exception + */ + public void testDoChangeSessionDeliveryMode() throws Exception { + Destination destination = createDestination("foo.bar"); + Connection connection = createConnection(); + connection.start(); + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer1 = consumerSession.createConsumer(destination); + consumer1.setMessageListener(this); + MessageConsumer consumer2 = consumerSession.createConsumer(destination); + + try { + consumer2.receive(10); + fail("Did not receive expected exception."); + } catch (JMSException e) { + assertTrue(e instanceof IllegalStateException); + } + } + + @Override + public void onMessage(Message msg) { + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ClientRebalanceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ClientRebalanceTest.java new file mode 100644 index 0000000000..e00eb70b10 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ClientRebalanceTest.java @@ -0,0 +1,90 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.log4j.Logger; +import org.springframework.core.io.ClassPathResource; + +public class ClientRebalanceTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = Logger.getLogger(ClientRebalanceTest.class); + private static final String QUEUE_NAME = "Test.ClientRebalanceTest"; + + 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")); + + startAllBrokers(); + + brokers.get("b1").broker.waitUntilStarted(); + + LOG.info("Starting connection"); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616,tcp://localhost:61617)?randomize=false"); + 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"); + producer.send(message); + Message msg = consumer.receive(2000); + assertNotNull(msg); + + // introduce third broker + createBroker(new ClassPathResource("org/apache/activemq/usecases/rebalance-broker3.xml")); + brokers.get("b3").broker.waitUntilStarted(); + + Thread.sleep(3000); + + 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); + + LOG.info("Stopping broker 2"); + + brokers.get("b2").broker.stop(); + brokers.get("b2").broker.waitUntilStopped(); + + // should reconnect to broker3 + producer.send(message); + msg = consumer.receive(2000); + assertNotNull(msg); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CompositeConsumeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CompositeConsumeTest.java new file mode 100644 index 0000000000..add5a3c379 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CompositeConsumeTest.java @@ -0,0 +1,74 @@ +/** + * 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.usecases; + +import javax.jms.Destination; +import javax.jms.Message; + +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; +import org.apache.activemq.transport.udp.UdpTransportUsingServerTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class CompositeConsumeTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + private static final Logger LOG = LoggerFactory.getLogger(CompositeConsumeTest.class); + + public void testSendReceive() throws Exception { + messages.clear(); + + Destination[] destinations = getDestinations(); + int destIdx = 0; + + for (int i = 0; i < data.length; i++) { + Message message = session.createTextMessage(data[i]); + + if (verbose) { + LOG.info("About to send a message: " + message + " with text: " + data[i]); + } + + producer.send(destinations[destIdx], message); + + if (++destIdx >= destinations.length) { + destIdx = 0; + } + } + + assertMessagesAreReceived(); + } + + /** + * Returns the subscription subject + */ + protected String getSubject() { + return getPrefix() + "FOO.BAR," + getPrefix() + "FOO.X.Y," + getPrefix() + "BAR.>"; + } + + /** + * Returns the destinations on which we publish + */ + protected Destination[] getDestinations() { + return new Destination[]{new ActiveMQTopic(getPrefix() + "FOO.BAR"), new ActiveMQTopic(getPrefix() + "BAR.WHATNOT.XYZ"), new ActiveMQTopic(getPrefix() + "FOO.X.Y")}; + } + + protected String getPrefix() { + return super.getSubject() + "."; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CompositePublishTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CompositePublishTest.java new file mode 100644 index 0000000000..2018a5d916 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CompositePublishTest.java @@ -0,0 +1,153 @@ +/** + * 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.usecases; + +import java.util.List; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.test.JmsSendReceiveTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class CompositePublishTest extends JmsSendReceiveTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(CompositePublishTest.class); + + protected Connection sendConnection; + protected Connection receiveConnection; + protected Session receiveSession; + protected MessageConsumer[] consumers; + @SuppressWarnings("rawtypes") + protected List[] messageLists; + + @SuppressWarnings("unchecked") + @Override + protected void setUp() throws Exception { + super.setUp(); + + connectionFactory = createConnectionFactory(); + + sendConnection = createConnection(); + sendConnection.start(); + + receiveConnection = createConnection(); + receiveConnection.start(); + + LOG.info("Created sendConnection: " + sendConnection); + LOG.info("Created receiveConnection: " + receiveConnection); + + session = sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + receiveSession = receiveConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + LOG.info("Created sendSession: " + session); + LOG.info("Created receiveSession: " + receiveSession); + + producer = session.createProducer(null); + + LOG.info("Created producer: " + producer); + + if (topic) { + consumerDestination = session.createTopic(getConsumerSubject()); + producerDestination = session.createTopic(getProducerSubject()); + } else { + consumerDestination = session.createQueue(getConsumerSubject()); + producerDestination = session.createQueue(getProducerSubject()); + } + + LOG.info("Created consumer destination: " + consumerDestination + " of type: " + consumerDestination.getClass()); + LOG.info("Created producer destination: " + producerDestination + " of type: " + producerDestination.getClass()); + + Destination[] destinations = getDestinations(); + consumers = new MessageConsumer[destinations.length]; + messageLists = new List[destinations.length]; + for (int i = 0; i < destinations.length; i++) { + Destination dest = destinations[i]; + messageLists[i] = createConcurrentList(); + consumers[i] = receiveSession.createConsumer(dest); + consumers[i].setMessageListener(createMessageListener(i, messageLists[i])); + } + + LOG.info("Started connections"); + } + + protected MessageListener createMessageListener(int i, final List messageList) { + return new MessageListener() { + @Override + public void onMessage(Message message) { + consumeMessage(message, messageList); + } + }; + } + + /** + * Returns the subject on which we publish + */ + @Override + protected String getSubject() { + return getPrefix() + "FOO.BAR," + getPrefix() + "FOO.X.Y"; + } + + /** + * Returns the destinations to which we consume + */ + protected Destination[] getDestinations() { + return new Destination[] {new ActiveMQTopic(getPrefix() + "FOO.BAR"), new ActiveMQTopic(getPrefix() + "FOO.*"), new ActiveMQTopic(getPrefix() + "FOO.X.Y")}; + } + + protected String getPrefix() { + return super.getSubject() + "."; + } + + @SuppressWarnings("unchecked") + @Override + protected void assertMessagesAreReceived() throws JMSException { + waitForMessagesToBeDelivered(); + int size = messageLists.length; + for (int i = 0; i < size; i++) { + LOG.info("Message list: " + i + " contains: " + messageLists[i].size() + " message(s)"); + } + size = messageLists.length; + for (int i = 0; i < size; i++) { + assertMessagesReceivedAreValid(messageLists[i]); + } + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() { + return new ActiveMQConnectionFactory("vm://localhost"); + } + + @Override + protected void tearDown() throws Exception { + session.close(); + receiveSession.close(); + + sendConnection.close(); + receiveConnection.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentDestinationCreationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentDestinationCreationTest.java new file mode 100644 index 0000000000..eb9e5d4144 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentDestinationCreationTest.java @@ -0,0 +1,152 @@ +/** + * 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.usecases; + + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConcurrentDestinationCreationTest extends org.apache.activemq.TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ConcurrentDestinationCreationTest.class); + BrokerService broker; + + @Override + protected void setUp() throws Exception { + broker = createBroker(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + broker.stop(); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getPublishableConnectString() + "?jms.watchTopicAdvisories=false&jms.closeTimeout=35000"); + } + + BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setDeleteAllMessagesOnStartup(true); + service.setAdvisorySupport(false); + service.setTransportConnectorURIs(new String[]{"tcp://localhost:0"}); + service.setPersistent(false); + service.setUseJmx(false); + service.start(); + return service; + } + + public void testSendRateWithActivatingConsumers() throws Exception { + + final Vector exceptions = new Vector(); + final int jobs = 50; + final int destinationCount = 10; + final CountDownLatch allDone = new CountDownLatch(jobs); + ExecutorService executor = java.util.concurrent.Executors.newCachedThreadPool(); + for (int i = 0; i < jobs; i++) { + if (i %2 == 0 && i")); + consumer.receiveNoWait(); + } + connection.close(); + allDone.countDown(); + LOG.info("Consumers done!"); + } catch (Exception ignored) { + LOG.error("unexpected ", ignored); + exceptions.add(ignored); + } + } + }); + } + } + LOG.info("Waiting for completion"); + executor.shutdown(); + boolean success = allDone.await(30, TimeUnit.SECONDS); + if (!success) { + dumpAllThreads("hung"); + + ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + LOG.info("Supports dead lock detection: " + bean.isSynchronizerUsageSupported()); + long[] threadIds = bean.findDeadlockedThreads(); + if (threadIds != null) { + System.err.println("Dead locked threads...."); + ThreadInfo[] infos = bean.getThreadInfo(threadIds); + + for (ThreadInfo info : infos) { + StackTraceElement[] stack = info.getStackTrace(); + System.err.println(" " + info + ", stack size::" + stack.length); + for (StackTraceElement stackEntry : stack) { + System.err.println(" " + stackEntry); + } + } + } + } + assertTrue("Finished on time", success); + assertTrue("No unexpected exceptions", exceptions.isEmpty()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentProducerDurableConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentProducerDurableConsumerTest.java new file mode 100644 index 0000000000..a5233ee14b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentProducerDurableConsumerTest.java @@ -0,0 +1,491 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.StorePendingDurableSubscriberMessageStoragePolicy; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class ConcurrentProducerDurableConsumerTest extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ConcurrentProducerDurableConsumerTest.class); + private final int consumerCount = 5; + BrokerService broker; + protected List connections = Collections.synchronizedList(new ArrayList()); + protected Map consumers = new HashMap(); + protected MessageIdList allMessagesList = new MessageIdList(); + private final int messageSize = 1024; + + private final TestSupport.PersistenceAdapterChoice persistenceAdapterChoice; + + @Parameterized.Parameters + public static Collection getTestParameters() { + TestSupport.PersistenceAdapterChoice[] kahaDb = {TestSupport.PersistenceAdapterChoice.KahaDB}; + TestSupport.PersistenceAdapterChoice[] levelDb = {TestSupport.PersistenceAdapterChoice.LevelDB}; + TestSupport.PersistenceAdapterChoice[] mem = {TestSupport.PersistenceAdapterChoice.MEM}; + List choices = new ArrayList(); + choices.add(kahaDb); + choices.add(levelDb); + choices.add(mem); + return choices; + } + + public ConcurrentProducerDurableConsumerTest(TestSupport.PersistenceAdapterChoice choice) { + this.persistenceAdapterChoice = choice; + } + + @Test(timeout = 120000) + public void testSendRateWithActivatingConsumers() throws Exception { + final Destination destination = createDestination(); + final ConnectionFactory factory = createConnectionFactory(); + startInactiveConsumers(factory, destination); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = createMessageProducer(session, destination); + + // preload the durable consumers + double[] inactiveConsumerStats = produceMessages(destination, 500, 10, session, producer, null); + LOG.info("With inactive consumers: ave: " + inactiveConsumerStats[1] + + ", max: " + inactiveConsumerStats[0] + ", multiplier: " + (inactiveConsumerStats[0]/inactiveConsumerStats[1])); + + // periodically start a durable sub that has a backlog + final int consumersToActivate = 5; + final Object addConsumerSignal = new Object(); + Executors.newCachedThreadPool(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "ActivateConsumer" + this); + } + }).execute(new Runnable() { + @Override + public void run() { + try { + MessageConsumer consumer = null; + for (int i = 0; i < consumersToActivate; i++) { + LOG.info("Waiting for add signal from producer..."); + synchronized (addConsumerSignal) { + addConsumerSignal.wait(30 * 60 * 1000); + } + TimedMessageListener listener = new TimedMessageListener(); + consumer = createDurableSubscriber(factory.createConnection(), destination, "consumer" + (i + 1)); + LOG.info("Created consumer " + consumer); + consumer.setMessageListener(listener); + consumers.put(consumer, listener); + } + } catch (Exception e) { + LOG.error("failed to start consumer", e); + } + } + }); + + double[] statsWithActive = produceMessages(destination, 500, 10, session, producer, addConsumerSignal); + + LOG.info(" with concurrent activate, ave: " + statsWithActive[1] + ", max: " + statsWithActive[0] + ", multiplier: " + (statsWithActive[0]/ statsWithActive[1])); + + while(consumers.size() < consumersToActivate) { + TimeUnit.SECONDS.sleep(2); + } + + long timeToFirstAccumulator = 0; + for (TimedMessageListener listener : consumers.values()) { + long time = listener.getFirstReceipt(); + timeToFirstAccumulator += time; + LOG.info("Time to first " + time); + } + LOG.info("Ave time to first message =" + timeToFirstAccumulator/consumers.size()); + + for (TimedMessageListener listener : consumers.values()) { + LOG.info("Ave batch receipt time: " + listener.waitForReceivedLimit(10000) + " max receipt: " + listener.maxReceiptTime); + } + + //assertTrue("max (" + statsWithActive[0] + ") within reasonable multiplier of ave (" + statsWithActive[1] + ")", + // statsWithActive[0] < 5 * statsWithActive[1]); + + // compare no active to active + LOG.info("Ave send time with active: " + statsWithActive[1] + + " as multiplier of ave with none active: " + inactiveConsumerStats[1] + + ", multiplier=" + (statsWithActive[1]/inactiveConsumerStats[1])); + + assertTrue("Ave send time with active: " + statsWithActive[1] + + " within reasonable multpler of ave with none active: " + inactiveConsumerStats[1] + + ", multiplier " + (statsWithActive[1]/inactiveConsumerStats[1]), + statsWithActive[1] < 15 * inactiveConsumerStats[1]); + } + + public void x_testSendWithInactiveAndActiveConsumers() throws Exception { + Destination destination = createDestination(); + ConnectionFactory factory = createConnectionFactory(); + startInactiveConsumers(factory, destination); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + final int toSend = 100; + final int numIterations = 5; + + double[] noConsumerStats = produceMessages(destination, toSend, numIterations, session, producer, null); + + startConsumers(factory, destination); + LOG.info("Activated consumer"); + + double[] withConsumerStats = produceMessages(destination, toSend, numIterations, session, producer, null); + + LOG.info("With consumer: " + withConsumerStats[1] + " , with noConsumer: " + noConsumerStats[1] + + ", multiplier: " + (withConsumerStats[1]/noConsumerStats[1])); + final int reasonableMultiplier = 15; // not so reasonable but improving + assertTrue("max X times as slow with consumer: " + withConsumerStats[1] + ", with no Consumer: " + + noConsumerStats[1] + ", multiplier: " + (withConsumerStats[1]/noConsumerStats[1]), + withConsumerStats[1] < noConsumerStats[1] * reasonableMultiplier); + + final int toReceive = toSend * numIterations * consumerCount * 2; + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("count: " + allMessagesList.getMessageCount()); + return toReceive == allMessagesList.getMessageCount(); + } + }, 60 * 1000); + + assertEquals("got all messages", toReceive, allMessagesList.getMessageCount()); + } + + private MessageProducer createMessageProducer(Session session, Destination destination) throws JMSException { + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + return producer; + } + + private void startInactiveConsumers(ConnectionFactory factory, Destination destination) throws Exception { + // create off line consumers + startConsumers(factory, destination); + for (Connection connection: connections) { + connection.close(); + } + connections.clear(); + consumers.clear(); + } + + protected void startConsumers(ConnectionFactory factory, Destination dest) throws Exception { + MessageConsumer consumer; + for (int i = 0; i < consumerCount; i++) { + TimedMessageListener list = new TimedMessageListener(); + consumer = createDurableSubscriber(factory.createConnection(), dest, "consumer" + (i + 1)); + consumer.setMessageListener(list); + consumers.put(consumer, list); + } + } + + protected TopicSubscriber createDurableSubscriber(Connection conn, Destination dest, String name) throws Exception { + conn.setClientID(name); + connections.add(conn); + conn.start(); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSubscriber consumer = sess.createDurableSubscriber((javax.jms.Topic)dest, name); + + return consumer; + } + + /** + * @return max and ave send time + * @throws Exception + */ + private double[] produceMessages(Destination destination, + final int toSend, + final int numIterations, + Session session, + MessageProducer producer, + Object addConsumerSignal) throws Exception { + long start; + long count = 0; + double batchMax = 0, max = 0, sum = 0; + for (int i=0; i iter = connections.iterator(); iter.hasNext();) { + Connection conn = iter.next(); + try { + conn.close(); + } catch (Throwable e) { + } + } + broker.stop(); + allMessagesList.flushMessages(); + consumers.clear(); + super.tearDown(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService brokerService = new BrokerService(); + brokerService.setEnableStatistics(false); + brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.setDeleteAllMessagesOnStartup(true); + + PolicyEntry policy = new PolicyEntry(); + policy.setPrioritizedMessages(true); + policy.setMaxPageSize(500); + + StorePendingDurableSubscriberMessageStoragePolicy durableSubPending = + new StorePendingDurableSubscriberMessageStoragePolicy(); + durableSubPending.setImmediatePriorityDispatch(true); + durableSubPending.setUseCache(true); + policy.setPendingDurableSubscriberPolicy(durableSubPending); + + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(policy); + brokerService.setDestinationPolicy(policyMap); + +// if (false) { +// // external mysql works a lot faster +// // +// JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); +// BasicDataSource ds = new BasicDataSource(); +// com.mysql.jdbc.Driver d = new com.mysql.jdbc.Driver(); +// ds.setDriverClassName("com.mysql.jdbc.Driver"); +// ds.setUrl("jdbc:mysql://localhost/activemq?relaxAutoCommit=true"); +// ds.setMaxActive(200); +// ds.setUsername("root"); +// ds.setPassword(""); +// ds.setPoolPreparedStatements(true); +// jdbc.setDataSource(ds); +// brokerService.setPersistenceAdapter(jdbc); + + /* add mysql bits to the pom in the testing dependencies + + mysql + mysql-connector-java + 5.1.10 + test + + + commons-dbcp + commons-dbcp + 1.2.2 + test + + */ +// } else { + setPersistenceAdapter(brokerService, persistenceAdapterChoice); +// } + return brokerService; + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getPublishableConnectString()); + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setAll(1); + factory.setPrefetchPolicy(prefetchPolicy); + + factory.setDispatchAsync(true); + return factory; + } + + class TimedMessageListener implements MessageListener { + final int batchSize = 1000; + CountDownLatch firstReceiptLatch = new CountDownLatch(1); + long mark = System.currentTimeMillis(); + long firstReceipt = 0l; + long receiptAccumulator = 0; + long batchReceiptAccumulator = 0; + long maxReceiptTime = 0; + AtomicLong count = new AtomicLong(0); + Map messageLists = new ConcurrentHashMap(new HashMap()); + + @Override + public void onMessage(Message message) { + final long current = System.currentTimeMillis(); + final long duration = current - mark; + receiptAccumulator += duration; + int priority = 0; + try { + priority = message.getJMSPriority(); + } catch (JMSException ignored) {} + if (!messageLists.containsKey(priority)) { + MessageIdList perPriorityList = new MessageIdList(); + perPriorityList.setParent(allMessagesList); + messageLists.put(priority, perPriorityList); + } + messageLists.get(priority).onMessage(message); + if (count.incrementAndGet() == 1) { + firstReceipt = duration; + firstReceiptLatch.countDown(); + LOG.info("First receipt in " + firstReceipt + "ms"); + } else if (count.get() % batchSize == 0) { + LOG.info("Consumed " + count.get() + " in " + batchReceiptAccumulator + "ms" + ", priority:" + priority); + batchReceiptAccumulator=0; + } + maxReceiptTime = Math.max(maxReceiptTime, duration); + receiptAccumulator += duration; + batchReceiptAccumulator += duration; + mark = current; + } + + long getMessageCount() { + return count.get(); + } + + long getFirstReceipt() throws Exception { + firstReceiptLatch.await(30, TimeUnit.SECONDS); + return firstReceipt; + } + + public long waitForReceivedLimit(long limit) throws Exception { + final long expiry = System.currentTimeMillis() + 30*60*1000; + while (count.get() < limit) { + if (System.currentTimeMillis() > expiry) { + throw new RuntimeException("Expired waiting for X messages, " + limit); + } + TimeUnit.SECONDS.sleep(2); + String missing = findFirstMissingMessage(); + if (missing != null) { + LOG.info("first missing = " + missing); + throw new RuntimeException("We have a missing message. " + missing); + } + + } + return receiptAccumulator/(limit/batchSize); + } + + private String findFirstMissingMessage() { + MessageId current = new MessageId(); + for (MessageIdList priorityList : messageLists.values()) { + MessageId previous = null; + for (String id : priorityList.getMessageIds()) { + current.setValue(id); + if (previous == null) { + previous = current.copy(); + } else { + if (current.getProducerSequenceId() - 1 != previous.getProducerSequenceId() && + current.getProducerSequenceId() - 10 != previous.getProducerSequenceId()) { + return "Missing next after: " + previous + ", got: " + current; + } else { + previous = current.copy(); + } + } + } + } + return null; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentProducerQueueConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentProducerQueueConsumerTest.java new file mode 100644 index 0000000000..e9e3b54dea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConcurrentProducerQueueConsumerTest.java @@ -0,0 +1,435 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConcurrentProducerQueueConsumerTest extends TestSupport +{ + private static final Logger LOG = LoggerFactory.getLogger(ConcurrentProducerQueueConsumerTest.class); + + protected List connections = Collections.synchronizedList(new ArrayList()); + protected Map consumers = + new HashMap(); + protected MessageIdList allMessagesList = new MessageIdList(); + + private BrokerService broker; + private final int consumerCount = 5; + private final int messageSize = 1024; + private final int NUM_MESSAGES = 500; + private final int ITERATIONS = 10; + + private int expectedQueueDeliveries = 0; + + public void initCombosForTestSendRateWithActivatingConsumers() throws Exception { + addCombinationValues("defaultPersistenceAdapter", + new Object[]{PersistenceAdapterChoice.KahaDB, PersistenceAdapterChoice.LevelDB, + /* too slow for hudson - PersistenceAdapterChoice.JDBC,*/ + PersistenceAdapterChoice.MEM}); + } + + public void testSendRateWithActivatingConsumers() throws Exception { + final Destination destination = createDestination(); + final ConnectionFactory factory = createConnectionFactory(); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = createMessageProducer(session, destination); + + // preload the queue before adding any consumers + double[] noConsumerStats = produceMessages(destination, NUM_MESSAGES, ITERATIONS, session, producer, null); + LOG.info("With no consumers: ave: " + noConsumerStats[1] + ", max: " + + noConsumerStats[0] + ", multiplier: " + (noConsumerStats[0]/noConsumerStats[1])); + expectedQueueDeliveries = NUM_MESSAGES * ITERATIONS; + + // periodically start a queue consumer + final int consumersToActivate = 5; + final Object addConsumerSignal = new Object(); + Executors.newCachedThreadPool(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "ActivateConsumer" + this); + } + }).execute(new Runnable() { + @Override + public void run() { + try { + MessageConsumer consumer = null; + for (int i = 0; i < consumersToActivate; i++) { + LOG.info("Waiting for add signal from producer..."); + synchronized (addConsumerSignal) { + addConsumerSignal.wait(30 * 60 * 1000); + } + TimedMessageListener listener = new TimedMessageListener(); + consumer = createConsumer(factory.createConnection(), destination); + LOG.info("Created consumer " + consumer); + consumer.setMessageListener(listener); + consumers.put(consumer, listener); + } + } catch (Exception e) { + LOG.error("failed to start consumer", e); + } + } + }); + + // Collect statistics when there are active consumers. + double[] statsWithActive = + produceMessages(destination, NUM_MESSAGES, ITERATIONS, session, producer, addConsumerSignal); + expectedQueueDeliveries += NUM_MESSAGES * ITERATIONS; + + LOG.info(" with concurrent activate, ave: " + statsWithActive[1] + ", max: " + + statsWithActive[0] + ", multiplier: " + (statsWithActive[0]/ statsWithActive[1])); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return consumers.size() == consumersToActivate; + } + })); + + long timeToFirstAccumulator = 0; + for (TimedMessageListener listener : consumers.values()) { + long time = listener.getFirstReceipt(); + timeToFirstAccumulator += time; + LOG.info("Time to first " + time); + } + LOG.info("Ave time to first message =" + timeToFirstAccumulator/consumers.size()); + + for (TimedMessageListener listener : consumers.values()) { + LOG.info("Ave batch receipt time: " + listener.waitForReceivedLimit(expectedQueueDeliveries) + + " max receipt: " + listener.maxReceiptTime); + } + + // compare no active to active + LOG.info("Ave send time with active: " + statsWithActive[1] + + " as multiplier of ave with none active: " + noConsumerStats[1] + + ", multiplier=" + (statsWithActive[1]/noConsumerStats[1])); + + assertTrue("Ave send time with active: " + statsWithActive[1] + + " within reasonable multpler of ave with none active: " + noConsumerStats[1] + + ", multiplier " + (statsWithActive[1]/noConsumerStats[1]), + statsWithActive[1] < 15 * noConsumerStats[1]); + } + + public void x_initCombosForTestSendWithInactiveAndActiveConsumers() throws Exception { + addCombinationValues("defaultPersistenceAdapter", + new Object[]{PersistenceAdapterChoice.KahaDB, PersistenceAdapterChoice.LevelDB, + /* too slow for hudson - PersistenceAdapterChoice.JDBC,*/ + PersistenceAdapterChoice.MEM}); + } + + public void x_testSendWithInactiveAndActiveConsumers() throws Exception { + Destination destination = createDestination(); + ConnectionFactory factory = createConnectionFactory(); + + Connection connection = factory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + final int toSend = 100; + final int numIterations = 5; + + double[] noConsumerStats = produceMessages(destination, toSend, numIterations, session, producer, null); + + startConsumers(factory, destination); + LOG.info("Activated consumer"); + + double[] withConsumerStats = produceMessages(destination, toSend, numIterations, session, producer, null); + + LOG.info("With consumer: " + withConsumerStats[1] + " , with noConsumer: " + noConsumerStats[1] + + ", multiplier: " + (withConsumerStats[1]/noConsumerStats[1])); + final int reasonableMultiplier = 15; // not so reasonable but improving + assertTrue("max X times as slow with consumer: " + withConsumerStats[1] + ", with no Consumer: " + + noConsumerStats[1] + ", multiplier: " + (withConsumerStats[1]/noConsumerStats[1]), + withConsumerStats[1] < noConsumerStats[1] * reasonableMultiplier); + + final int toReceive = toSend * numIterations * consumerCount * 2; + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + LOG.info("count: " + allMessagesList.getMessageCount()); + return toReceive == allMessagesList.getMessageCount(); + } + }, 60 * 1000); + + assertEquals("got all messages", toReceive, allMessagesList.getMessageCount()); + } + + private MessageProducer createMessageProducer(Session session, Destination destination) throws JMSException { + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + return producer; + } + + protected void startConsumers(ConnectionFactory factory, Destination dest) throws Exception { + MessageConsumer consumer; + for (int i = 0; i < consumerCount; i++) { + TimedMessageListener list = new TimedMessageListener(); + consumer = createConsumer(factory.createConnection(), dest); + consumer.setMessageListener(list); + consumers.put(consumer, list); + } + } + + protected MessageConsumer createConsumer(Connection conn, Destination dest) throws Exception { + connections.add(conn); + conn.start(); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = sess.createConsumer(dest); + + return consumer; + } + + /** + * @return max and average send time + * @throws Exception + */ + private double[] produceMessages(Destination destination, + final int toSend, + final int numIterations, + Session session, + MessageProducer producer, + Object addConsumerSignal) throws Exception { + long start; + long count = 0; + double batchMax = 0, max = 0, sum = 0; + + for (int i=0; i iter = connections.iterator(); iter.hasNext();) { + Connection conn = iter.next(); + try { + conn.close(); + } catch (Throwable e) { + } + } + broker.stop(); + allMessagesList.flushMessages(); + consumers.clear(); + super.tearDown(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService brokerService = new BrokerService(); + brokerService.setEnableStatistics(false); + brokerService.addConnector("tcp://0.0.0.0:0"); + brokerService.setDeleteAllMessagesOnStartup(true); + + PolicyEntry policy = new PolicyEntry(); + policy.setPrioritizedMessages(true); + policy.setMaxPageSize(500); + + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(policy); + brokerService.setDestinationPolicy(policyMap); + setDefaultPersistenceAdapter(brokerService); + + return brokerService; + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + broker.getTransportConnectors().get(0).getPublishableConnectString()); + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setAll(1); + factory.setPrefetchPolicy(prefetchPolicy); + + factory.setDispatchAsync(true); + return factory; + } + + public static Test suite() { + return suite(ConcurrentProducerQueueConsumerTest.class); + } + + static class TimedMessageListener implements MessageListener { + + static final AtomicLong count = new AtomicLong(0); + + final int batchSize = 1000; + final CountDownLatch firstReceiptLatch = new CountDownLatch(1); + + long mark = System.currentTimeMillis(); + long firstReceipt = 0l; + long receiptAccumulator = 0; + long batchReceiptAccumulator = 0; + long maxReceiptTime = 0; + + final Map messageLists = + new ConcurrentHashMap(new HashMap()); + + @Override + public void onMessage(Message message) { + final long current = System.currentTimeMillis(); + final long duration = current - mark; + receiptAccumulator += duration; + int priority = 0; + + try { + priority = message.getJMSPriority(); + } catch (JMSException ignored) {} + + if (!messageLists.containsKey(priority)) { + messageLists.put(priority, new MessageIdList()); + } + messageLists.get(priority).onMessage(message); + + if (count.incrementAndGet() == 1) { + firstReceipt = duration; + firstReceiptLatch.countDown(); + LOG.info("First receipt in " + firstReceipt + "ms"); + } else if (count.get() % batchSize == 0) { + LOG.info("Consumed " + count.get() + " in " + batchReceiptAccumulator + "ms" + ", priority:" + priority); + batchReceiptAccumulator=0; + } + + maxReceiptTime = Math.max(maxReceiptTime, duration); + receiptAccumulator += duration; + batchReceiptAccumulator += duration; + mark = current; + } + + long getMessageCount() { + return count.get(); + } + + long getFirstReceipt() throws Exception { + firstReceiptLatch.await(30, TimeUnit.SECONDS); + return firstReceipt; + } + + public long waitForReceivedLimit(long limit) throws Exception { + final long expiry = System.currentTimeMillis() + 30*60*1000; + while (count.get() < limit) { + if (System.currentTimeMillis() > expiry) { + throw new RuntimeException("Expired waiting for X messages, " + limit); + } + TimeUnit.SECONDS.sleep(2); + String missing = findFirstMissingMessage(); + if (missing != null) { + LOG.info("first missing = " + missing); + throw new RuntimeException("We have a missing message. " + missing); + } + + } + return receiptAccumulator/(limit/batchSize); + } + + private String findFirstMissingMessage() { + return null; + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeQueuePrefetchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeQueuePrefetchTest.java new file mode 100644 index 0000000000..3810505523 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeQueuePrefetchTest.java @@ -0,0 +1,57 @@ +/** + * 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.usecases; + +import javax.jms.JMSException; +import javax.jms.Message; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConsumeQueuePrefetchTest extends ConsumeTopicPrefetchTest { + private static final Logger LOG = LoggerFactory.getLogger(ConsumeQueuePrefetchTest.class); + + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } + + public void testInflightWithConsumerPerMessage() throws JMSException { + makeMessages(prefetchSize); + + LOG.info("About to send and receive: " + prefetchSize + " on destination: " + destination + + " of type: " + destination.getClass().getName()); + + for (int i = 0; i < prefetchSize; i++) { + Message message = session.createTextMessage(messageTexts[i]); + producer.send(message); + } + + validateConsumerPrefetch(this.getSubject(), prefetchSize); + + // new consumer per 20 messages + for (int i = 0; i < prefetchSize; i+=20) { + consumer.close(); + consumer = session.createConsumer(destination); + validateConsumerPrefetch(this.getSubject(), prefetchSize - i); + for (int j=0; j<20; j++) { + Message message = consumeMessge(i+j); + message.acknowledge(); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeTopicPrefetchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeTopicPrefetchTest.java new file mode 100644 index 0000000000..d95d2d6d47 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeTopicPrefetchTest.java @@ -0,0 +1,154 @@ +/** + * 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.usecases; + +import java.util.LinkedList; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerRegistry; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.util.Wait; +import org.apache.activemq.util.Wait.Condition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ConsumeTopicPrefetchTest extends ProducerConsumerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ConsumeTopicPrefetchTest.class); + + protected int prefetchSize = 100; + protected String[] messageTexts; + protected long consumerTimeout = 10000L; + + public void testSendPrefetchSize() throws JMSException { + testWithMessageCount(prefetchSize); + } + + public void testSendDoublePrefetchSize() throws JMSException { + testWithMessageCount(prefetchSize * 2); + } + + public void testSendPrefetchSizePlusOne() throws JMSException { + testWithMessageCount(prefetchSize + 1); + } + + protected void testWithMessageCount(int messageCount) throws JMSException { + makeMessages(messageCount); + + LOG.info("About to send and receive: " + messageCount + " on destination: " + destination + + " of type: " + destination.getClass().getName()); + + for (int i = 0; i < messageCount; i++) { + Message message = session.createTextMessage(messageTexts[i]); + producer.send(message); + } + + validateConsumerPrefetch(this.getSubject(), prefetchSize); + + LinkedList consumed = new LinkedList(); + // lets consume them in two fetch batches + int batchSize = messageCount/2; + for (int i = 0; i < batchSize; i++) { + consumed.add(consumeMessge(i)); + } + + // delayed delivered ack a .5 prefetch + validateConsumerPrefetchGreaterOrEqual(this.getSubject(), (long) Math.min(messageCount, 1.5 * prefetchSize)); + + for (int i = 0; i < batchSize; i++) { + consumed.remove().acknowledge(); + } + + // second batch to consume the rest + for (int i = batchSize; i < messageCount; i++) { + consumeMessge(i).acknowledge(); + } + validateConsumerPrefetch(this.getSubject(), 0); + } + + protected Connection createConnection() throws Exception { + ActiveMQConnection connection = (ActiveMQConnection) super.createConnection(); + connection.getPrefetchPolicy().setQueuePrefetch(prefetchSize); + connection.getPrefetchPolicy().setTopicPrefetch(prefetchSize); + return connection; + } + + protected TextMessage consumeMessge(int i) throws JMSException { + Message message = consumer.receive(consumerTimeout); + assertTrue("Should have received a message by now for message: " + i, message != null); + assertTrue("Should be a TextMessage: " + message, message instanceof TextMessage); + TextMessage textMessage = (TextMessage) message; + assertEquals("Message content", messageTexts[i], textMessage.getText()); + return textMessage; + } + + + protected void makeMessages(int messageCount) { + messageTexts = new String[messageCount]; + for (int i = 0; i < messageCount; i++) { + messageTexts[i] = "Message for test: + " + getName() + " = " + i; + } + } + + private void validateConsumerPrefetchGreaterOrEqual(String subject, long min) throws JMSException { + doValidateConsumerPrefetch(subject, min, true); + } + + protected void validateConsumerPrefetch(String subject, final long expectedCount) throws JMSException { + doValidateConsumerPrefetch(subject, expectedCount, false); + } + + protected void doValidateConsumerPrefetch(String destination, final long expectedCount, final boolean greaterOrEqual) throws JMSException { + RegionBroker regionBroker = (RegionBroker) BrokerRegistry.getInstance().lookup("localhost").getRegionBroker(); + for (org.apache.activemq.broker.region.Destination dest : regionBroker.getTopicRegion().getDestinationMap().values()) { + final org.apache.activemq.broker.region.Destination target = dest; + if (dest.getName().equals(destination)) { + try { + Wait.waitFor(new Condition() { + public boolean isSatisified() throws Exception { + DestinationStatistics stats = target.getDestinationStatistics(); + LOG.info("inflight for : " + target.getName() + ": " + stats.getInflight().getCount()); + if (greaterOrEqual) { + return stats.getInflight().getCount() >= expectedCount; + } else { + return stats.getInflight().getCount() == expectedCount; + } + } + }); + } catch (Exception e) { + throw new JMSException(e.toString()); + } + DestinationStatistics stats = dest.getDestinationStatistics(); + LOG.info("inflight for : " + dest.getName() + ": " + stats.getInflight().getCount()); + if (greaterOrEqual) { + assertTrue("inflight for: " + dest.getName() + ": " + stats.getInflight().getCount() + " > " + stats.getInflight().getCount(), + stats.getInflight().getCount() >= expectedCount); + } else { + assertEquals("inflight for: " + dest.getName() + ": " + stats.getInflight().getCount() + " matches", + expectedCount, stats.getInflight().getCount()); + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeUncompressedCompressedMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeUncompressedCompressedMessageTest.java new file mode 100644 index 0000000000..3c3568853e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ConsumeUncompressedCompressedMessageTest.java @@ -0,0 +1,194 @@ +/** + * 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.usecases; + +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 java.net.URI; + +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.command.ActiveMQMessage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConsumeUncompressedCompressedMessageTest { + + private static final Logger LOG = LoggerFactory.getLogger(ConsumeUncompressedCompressedMessageTest.class); + + private BrokerService broker; + private URI tcpUri; + + ActiveMQConnectionFactory factory; + ActiveMQConnection connection; + Session session; + Queue queue; + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + broker.waitUntilStarted(); + + factory = new ActiveMQConnectionFactory(tcpUri); + factory.setUseCompression(true); + + connection = (ActiveMQConnection) factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + queue = session.createQueue("CompressionTestQueue"); + } + + @After + public void tearDown() throws Exception { + + if(connection != null) { + connection.close(); + } + + broker.stop(); + broker.waitUntilStopped(); + } + + protected BrokerService createBroker() throws Exception { + return createBroker(true); + } + + protected BrokerService createBroker(boolean delete) throws Exception { + BrokerService answer = new BrokerService(); + answer.setPersistent(false); + answer.setDeleteAllMessagesOnStartup(true); + answer.setSchedulerSupport(false); + answer.setUseJmx(true); + TransportConnector connector = answer.addConnector("tcp://localhost:0"); + tcpUri = connector.getConnectUri(); + return answer; + } + + @Test + public void testBrowseAndReceiveCompressedMessages() throws Exception { + + assertTrue(connection.isUseCompression()); + + createProducerAndSendMessages(1); + + QueueViewMBean queueView = getProxyToQueueViewMBean(); + + assertNotNull(queueView); + + CompositeData[] compdatalist = queueView.browse(); + if (compdatalist.length == 0) { + fail("There is no message in the queue:"); + } + + CompositeData cdata = compdatalist[0]; + + assertComplexData(0, cdata, "Text", "Test Text Message: " + 0); + + assertMessageAreCorrect(1); + } + + @Test + public void testReceiveAndResendWithCompressionOff() throws Exception { + + assertTrue(connection.isUseCompression()); + + createProducerAndSendMessages(1); + + MessageConsumer consumer = session.createConsumer(queue); + TextMessage message = (TextMessage) consumer.receive(5000); + + assertTrue(((ActiveMQMessage) message).isCompressed()); + + LOG.debug("Received Message with Text = " + message.getText()); + + connection.setUseCompression(false); + + MessageProducer producer = session.createProducer(queue); + producer.send(message); + producer.close(); + + message = (TextMessage) consumer.receive(5000); + + LOG.debug("Received Message with Text = " + message.getText()); + } + + protected void assertComplexData(int messageIndex, CompositeData cdata, String name, Object expected) { + Object value = cdata.get(name); + assertEquals("Message " + messageIndex + " CData field: " + name, expected, value); + } + + private void createProducerAndSendMessages(int numToSend) throws Exception { + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + for (int i = 0; i < numToSend; i++) { + TextMessage message = session.createTextMessage("Test Text Message: " + i); + if (i != 0 && i % 10000 == 0) { + LOG.info("sent: " + i); + } + producer.send(message); + } + producer.close(); + } + + private QueueViewMBean getProxyToQueueViewMBean() + throws MalformedObjectNameException, JMSException { + ObjectName queueViewMBeanName = new ObjectName("org.apache.activemq" + + ":destinationType=Queue,destinationName=" + queue.getQueueName() + + ",type=Broker,brokerName=localhost"); + QueueViewMBean proxy = (QueueViewMBean) broker.getManagementContext() + .newProxyInstance(queueViewMBeanName, QueueViewMBean.class, + true); + return proxy; + } + + private void assertMessageAreCorrect(int numToReceive) throws Exception { + MessageConsumer consumer = session.createConsumer(queue); + + try{ + + for (int i = 0; i < numToReceive; ++i) { + TextMessage message = (TextMessage) consumer.receive(5000); + assertNotNull(message); + assertEquals("Test Text Message: " + i, message.getText()); + } + + } finally { + consumer.close(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CreateLotsOfTemporaryQueuesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CreateLotsOfTemporaryQueuesTest.java new file mode 100644 index 0000000000..77b821e821 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CreateLotsOfTemporaryQueuesTest.java @@ -0,0 +1,67 @@ +/** + * 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.usecases; + +import javax.jms.Session; +import javax.jms.TemporaryQueue; + +import junit.framework.Test; +import junit.framework.TestSuite; +import junit.textui.TestRunner; +import org.apache.activemq.EmbeddedBrokerAndConnectionTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class CreateLotsOfTemporaryQueuesTest extends EmbeddedBrokerAndConnectionTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(CreateLotsOfTemporaryQueuesTest.class); + + private static int numberToCreate = 500; + private static long sleep = 20; + + public static void main(String[] args) { + configure(args); + TestRunner.run(suite()); + } + + public static Test suite() { + return new TestSuite(CreateLotsOfTemporaryQueuesTest.class); + } + + public void testCreateLotsOfTemporaryQueues() throws Exception { + LOG.info("Creating " + numberToCreate + " temporary queue(s)"); + + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + for (int i = 0; i < numberToCreate; i++) { + if (i % 1000 == 0) { + LOG.info("attempt " + i); + } + TemporaryQueue temporaryQueue = session.createTemporaryQueue(); + temporaryQueue.delete(); + Thread.sleep(sleep); + } + LOG.info("Created " + numberToCreate + " temporary queue(s)"); + } + + public static void configure(String[] args) { + if (args.length > 0) { + numberToCreate = Integer.parseInt(args[0]); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CreateTemporaryQueueBeforeStartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CreateTemporaryQueueBeforeStartTest.java new file mode 100644 index 0000000000..e2d961cf39 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/CreateTemporaryQueueBeforeStartTest.java @@ -0,0 +1,131 @@ +/** + * 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.usecases; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.Topic; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; + +/** + * @author Peter Henning + * + */ +public class CreateTemporaryQueueBeforeStartTest extends TestCase { + private final String bindAddress = "tcp://localhost:0"; + private String connectionUri; + private Connection connection; + private BrokerService broker = new BrokerService(); + + public void testCreateTemporaryQueue() throws Exception { + connection = createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createTemporaryQueue(); + assertTrue("No queue created!", queue != null); + Topic topic = session.createTemporaryTopic(); + assertTrue("No topic created!", topic != null); + } + + public void testTryToReproduceNullPointerBug() throws Exception { + String url = connectionUri; + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url); + QueueConnection queueConnection = factory.createQueueConnection(); + this.connection = queueConnection; + QueueSession session = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + session.createSender(null); // Unidentified + Queue receiverQueue = session.createTemporaryQueue(); + session.createReceiver(receiverQueue); + queueConnection.start(); + } + + public void testTemporaryQueueConsumer() throws Exception { + final int number = 20; + final AtomicInteger count = new AtomicInteger(0); + for (int i = 0; i < number; i++) { + Thread thread = new Thread(new Runnable() { + public void run() { + try { + QueueConnection connection = createConnection(); + QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createTemporaryQueue(); + session.createReceiver(queue); + connection.start(); + + if (count.incrementAndGet() >= number) { + synchronized (count) { + count.notify(); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + thread.start(); + } + int maxWaitTime = 20000; + synchronized (count) { + long waitTime = maxWaitTime; + long start = System.currentTimeMillis(); + while (count.get() < number) { + if (waitTime <= 0) { + break; + } else { + count.wait(waitTime); + waitTime = maxWaitTime - (System.currentTimeMillis() - start); + } + } + } + assertTrue("Unexpected count: " + count, count.get() == number); + } + + protected QueueConnection createConnection() throws Exception { + ActiveMQConnectionFactory factory = createConnectionFactory(); + return factory.createQueueConnection(); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(connectionUri); + } + + protected void setUp() throws Exception { + broker.setUseJmx(false); + broker.setPersistent(false); + connectionUri = broker.addConnector(bindAddress).getPublishableConnectString(); + broker.start(); + broker.waitUntilStarted(); + + super.setUp(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + broker.stop(); + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DiscriminatingConsumerLoadTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DiscriminatingConsumerLoadTest.java new file mode 100644 index 0000000000..5ea5518f13 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DiscriminatingConsumerLoadTest.java @@ -0,0 +1,310 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; + +/** + * Test case intended to demonstrate delivery interruption to queue consumers when a JMS selector leaves some messages + * on the queue (due to use of a JMS Selector) + * + * testNonDiscriminatingConsumer() demonstrates proper functionality for consumers that don't use a selector to qualify + * their input. + * + * testDiscriminatingConsumer() demonstrates the failure condition in which delivery to the consumer eventually halts. + * + * The expected behavior is for the delivery to the client to be maintained regardless of the depth of the queue, + * particularly when the messages in the queue do not meet the selector criteria of the client. + * + * https://issues.apache.org/activemq/browse/AMQ-2217 + * + */ +public class DiscriminatingConsumerLoadTest extends TestSupport { + + private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog(DiscriminatingConsumerLoadTest.class); + + private Connection producerConnection; + private Connection consumerConnection; + + public static final String JMSTYPE_EATME = "DiscriminatingLoadClient.EatMe"; + public static final String JMSTYPE_IGNOREME = "DiscriminatingLoadClient.IgnoreMe"; + + private final int testSize = 5000; // setting this to a small number will pass all tests + + BrokerService broker; + + @Override + protected void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + + // workaround is to ensure sufficient dispatch buffer for the destination + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultPolicy = new PolicyEntry(); + defaultPolicy.setMaxPageSize(testSize); + policyMap.setDefaultEntry(defaultPolicy); + broker.setDestinationPolicy(policyMap); + broker.start(); + + super.setUp(); + this.producerConnection = this.createConnection(); + this.consumerConnection = this.createConnection(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + if (producerConnection != null) { + producerConnection.close(); + producerConnection = null; + } + if (consumerConnection != null) { + consumerConnection.close(); + consumerConnection = null; + } + super.tearDown(); + broker.stop(); + } + + /** + * Test to check if a single consumer with no JMS selector will receive all intended messages + * + * @throws java.lang.Exception + */ + public void testNonDiscriminatingConsumer() throws Exception { + + consumerConnection = createConnection(); + consumerConnection.start(); + LOG.info("consumerConnection = " + consumerConnection); + + try { + Thread.sleep(1000); + } catch (Exception e) { + } + + // here we pass in null for the JMS selector + Consumer consumer = new Consumer(consumerConnection, null); + Thread consumerThread = new Thread(consumer); + + consumerThread.start(); + + producerConnection = createConnection(); + producerConnection.start(); + LOG.info("producerConnection = " + producerConnection); + + try { + Thread.sleep(3000); + } catch (Exception e) { + } + + Producer producer = new Producer(producerConnection); + Thread producerThread = new Thread(producer); + producerThread.start(); + + // now that everything is running, let's wait for the consumer thread to finish ... + consumerThread.join(); + producer.stop = true; + + if (consumer.getCount() == testSize) + LOG.info("test complete .... all messsages consumed!!"); + else + LOG.info("test failed .... Sent " + (testSize / 1) + " messages intended to be consumed ( " + testSize + " total), but only consumed " + + consumer.getCount()); + + assertTrue("Sent " + testSize + " messages intended to be consumed, but only consumed " + consumer.getCount(), (consumer.getCount() == testSize)); + assertFalse("Delivery of messages to consumer was halted during this test", consumer.deliveryHalted()); + } + + /** + * Test to check if a single consumer with a JMS selector will receive all intended messages + * + * @throws java.lang.Exception + */ + public void testDiscriminatingConsumer() throws Exception { + + consumerConnection = createConnection(); + consumerConnection.start(); + LOG.info("consumerConnection = " + consumerConnection); + + try { + Thread.sleep(1000); + } catch (Exception e) { + } + + // here we pass the JMS selector we intend to consume + Consumer consumer = new Consumer(consumerConnection, JMSTYPE_EATME); + Thread consumerThread = new Thread(consumer); + + consumerThread.start(); + + producerConnection = createConnection(); + producerConnection.start(); + LOG.info("producerConnection = " + producerConnection); + + try { + Thread.sleep(3000); + } catch (Exception e) { + } + + Producer producer = new Producer(producerConnection); + Thread producerThread = new Thread(producer); + producerThread.start(); + + // now that everything is running, let's wait for the consumer thread to finish ... + consumerThread.join(); + producer.stop = true; + + if (consumer.getCount() == (testSize / 2)) { + LOG.info("test complete .... all messsages consumed!!"); + } else { + LOG.info("test failed .... Sent " + testSize + " original messages, only half of which (" + (testSize / 2) + + ") were intended to be consumed: consumer paused at: " + consumer.getCount()); + // System.out.println("test failed .... Sent " + testSize + " original messages, only half of which (" + + // (testSize / 2) + + // ") were intended to be consumed: consumer paused at: " + consumer.getCount()); + + } + + assertTrue("Sent " + testSize + " original messages, only half of which (" + (testSize / 2) + ") were intended to be consumed: consumer paused at: " + + consumer.getCount(), (consumer.getCount() == (testSize / 2))); + assertTrue("Delivery of messages to consumer was halted during this test as it only wants half", consumer.deliveryHalted()); + } + + /** + * Helper class that will publish 2 * testSize messages. The messages will be distributed evenly between the + * following two JMS types: + * + * @see JMSTYPE_INTENDED_FOR_CONSUMPTION + * @see JMSTYPE_NOT_INTENDED_FOR_CONSUMPTION + * + */ + private class Producer extends Thread { + private int counterSent = 0; + private Connection connection = null; + public boolean stop = false; + + public Producer(Connection connection) { + this.connection = connection; + } + + @Override + public void run() { + try { + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue queue = session.createQueue("test"); + + // wait for 10 seconds to allow consumer.receive to be run + // first + Thread.sleep(10000); + MessageProducer producer = session.createProducer(queue); + + while (!stop && (counterSent < testSize)) { + // first send a message intended to be consumed .... + TextMessage message = session.createTextMessage("*** Ill ....... Ini ***"); // alma mater ... + message.setJMSType(JMSTYPE_EATME); + // LOG.info("sending .... JMSType = " + message.getJMSType()); + producer.send(message, DeliveryMode.NON_PERSISTENT, 0, 1800000); + + counterSent++; + + // now send a message intended to be consumed by some other consumer in the the future + // ... we expect these messages to accrue in the queue + message = session.createTextMessage("*** Ill ....... Ini ***"); // alma mater ... + message.setJMSType(JMSTYPE_IGNOREME); + // LOG.info("sending .... JMSType = " + message.getJMSType()); + producer.send(message, DeliveryMode.NON_PERSISTENT, 0, 1800000); + + counterSent++; + } + + session.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + LOG.info("producer thread complete ... " + counterSent + " messages sent to the queue"); + } + } + + /** + * Helper class that will consume messages from the queue based on the supplied JMS selector. Thread will stop after + * the first receive(..) timeout, or once all expected messages have been received (see testSize). If the thread + * stops due to a timeout, it is experiencing the delivery pause that is symptomatic of a bug in the broker. + * + */ + private class Consumer extends Thread { + protected int counterReceived = 0; + private String jmsSelector = null; + private boolean deliveryHalted = false; + + public Consumer(Connection connection, String jmsSelector) { + this.jmsSelector = jmsSelector; + } + + @Override + public void run() { + try { + Session session = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue queue = session.createQueue("test"); + MessageConsumer consumer = null; + if (null != this.jmsSelector) { + consumer = session.createConsumer(queue, "JMSType='" + this.jmsSelector + "'"); + } else { + consumer = session.createConsumer(queue); + } + + while (!deliveryHalted && (counterReceived < testSize)) { + TextMessage result = (TextMessage) consumer.receive(30000); + if (result != null) { + counterReceived++; + // System.out.println("consuming .... JMSType = " + result.getJMSType() + " received = " + + // counterReceived); + LOG.info("consuming .... JMSType = " + result.getJMSType() + " received = " + counterReceived); + } else { + LOG.info("consuming .... timeout while waiting for a message ... broker must have stopped delivery ... received = " + counterReceived); + deliveryHalted = true; + } + } + session.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public int getCount() { + return this.counterReceived; + } + + public boolean deliveryHalted() { + return this.deliveryHalted; + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DispatchMultipleConsumersTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DispatchMultipleConsumersTest.java new file mode 100644 index 0000000000..166049f71e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DispatchMultipleConsumersTest.java @@ -0,0 +1,227 @@ +/** + * 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.usecases; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Rajani Chennamaneni + */ +public class DispatchMultipleConsumersTest extends TestCase { + private final static Logger logger = LoggerFactory.getLogger(DispatchMultipleConsumersTest.class); + BrokerService broker; + Destination dest; + String destinationName = "TEST.Q"; + String msgStr = "Test text message"; + int messagesPerThread = 20; + int producerThreads = 50; + int consumerCount = 2; + AtomicInteger sentCount; + AtomicInteger consumedCount; + CountDownLatch producerLatch; + CountDownLatch consumerLatch; + String brokerURL; + String userName = ""; + String password = ""; + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + broker.setPersistent(true); + broker.setUseJmx(true); + broker.deleteAllMessages(); + broker.addConnector("tcp://localhost:0"); + broker.start(); + broker.waitUntilStarted(); + dest = new ActiveMQQueue(destinationName); + resetCounters(); + brokerURL = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + super.tearDown(); + } + + private void resetCounters() { + sentCount = new AtomicInteger(0); + consumedCount = new AtomicInteger(0); + producerLatch = new CountDownLatch(producerThreads); + consumerLatch = new CountDownLatch(consumerCount); + } + + public void testDispatch1() { + for (int i = 1; i <= 5; i++) { + resetCounters(); + dispatch(); + assertEquals("Incorrect messages in Iteration " + i, sentCount.get(), consumedCount.get()); + } + } + + private void dispatch() { + startConsumers(); + startProducers(); + try { + producerLatch.await(); + consumerLatch.await(); + } catch (InterruptedException e) { + fail("test interrupted!"); + } + } + + private void startConsumers() { + ActiveMQConnectionFactory connFactory = new ActiveMQConnectionFactory(userName, password, brokerURL); + Connection conn; + try { + conn = connFactory.createConnection(); + conn.start(); + for (int i = 0; i < consumerCount; i++) { + new ConsumerThread(conn, "ConsumerThread"+i); + } + } catch (JMSException e) { + logger.error("Failed to start consumers", e); + } + } + + private void startProducers() { + ActiveMQConnectionFactory connFactory = new ActiveMQConnectionFactory(userName, password, brokerURL); + for (int i = 0; i < producerThreads; i++) { + new ProducerThread(connFactory, messagesPerThread, "ProducerThread"+i); + } + } + + private class ConsumerThread extends Thread { + Session session; + MessageConsumer consumer; + + public ConsumerThread(Connection conn, String name) { + super(); + this.setName(name); + logger.trace("Created new consumer thread:" + name); + try { + session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createConsumer(dest); + start(); + } catch (JMSException e) { + logger.error("Failed to start consumer thread:" + name, e); + } + } + + @Override + public void run() { + int msgCount = 0; + int nullCount = 0; + while (true) { + try { + Message msg = consumer.receive(1000); + if (msg == null) { + if (producerLatch.getCount() > 0) { + continue; + } + nullCount++; + if (nullCount > 10) { + //assume that we are not getting any more messages + break; + } else { + continue; + } + } else { + nullCount = 0; + } + Thread.sleep(100); + if (logger.isTraceEnabled()) { + logger.trace("Message received:" + msg.getJMSMessageID()); + } + msgCount++; + } catch (JMSException e) { + logger.error("Failed to consume:", e); + } catch (InterruptedException e) { + logger.error("Interrupted!", e); + } + } + try { + consumer.close(); + } catch (JMSException e) { + logger.error("Failed to close consumer " + getName(), e); + } + consumedCount.addAndGet(msgCount); + consumerLatch.countDown(); + logger.trace("Consumed " + msgCount + " messages using thread " + getName()); + } + } + + private class ProducerThread extends Thread { + int count; + Connection conn; + Session session; + MessageProducer producer; + + public ProducerThread(ActiveMQConnectionFactory connFactory, int count, String name) { + super(); + this.count = count; + this.setName(name); + logger.trace("Created new producer thread:" + name); + try { + conn = connFactory.createConnection(); + conn.start(); + session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(dest); + start(); + } catch (JMSException e) { + logger.error("Failed to start producer thread:" + name, e); + } + } + + @Override + public void run() { + int i = 0; + try { + for (; i < count; i++) { + producer.send(session.createTextMessage(msgStr)); + Thread.sleep(500); + } + conn.close(); + } catch (JMSException e) { + logger.error(e.getMessage(), e); + } catch (InterruptedException e) { + logger.error("Interrupted!", e); + } + sentCount.addAndGet(i); + producerLatch.countDown(); + if (logger.isTraceEnabled()) { + logger.trace("Sent " + i + " messages from thread " + getName()); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableConsumerCloseAndReconnectTcpTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableConsumerCloseAndReconnectTcpTest.java new file mode 100644 index 0000000000..ac7bd62776 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableConsumerCloseAndReconnectTcpTest.java @@ -0,0 +1,193 @@ +/** + * 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.usecases; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.net.SocketFactory; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.transport.TransportFactory; +import org.apache.activemq.transport.TransportListener; +import org.apache.activemq.transport.tcp.TcpTransportFactory; +import org.apache.activemq.util.URISupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableConsumerCloseAndReconnectTcpTest extends DurableConsumerCloseAndReconnectTest +implements ExceptionListener, TransportListener { + private static final Logger LOG = LoggerFactory.getLogger(DurableConsumerCloseAndReconnectTcpTest.class); + + private BrokerService broker; + private TransportConnector connector; + + private CountDownLatch gotException = new CountDownLatch(1); + + private Exception reconnectException; + + private boolean reconnectInExceptionListener; + + private boolean reconnectInTransportListener; + + public void setUp() throws Exception { + broker = new BrokerService(); + // let the client initiate the inactivity timeout + connector = broker.addConnector("tcp://localhost:0?transport.useInactivityMonitor=false"); + broker.setPersistent(false); + broker.start(); + broker.waitUntilStarted(); + + class SlowCloseSocketTcpTransportFactory extends TcpTransportFactory { + + class SlowCloseSocketFactory extends SocketFactory { + + class SlowCloseSocket extends Socket { + public SlowCloseSocket(String host, int port) throws IOException { + super(host, port); + } + + public SlowCloseSocket(InetAddress host, int port) throws IOException { + super(host, port); + } + + public SlowCloseSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + super(host, port, localHost, localPort); + } + + public SlowCloseSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + super(address, port, localAddress, localPort); + } + + @Override + public synchronized void close() throws IOException { + LOG.info("delaying close"); + try { + TimeUnit.MILLISECONDS.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + super.close(); + } + + + } + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return new SlowCloseSocket(host, port); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return new SlowCloseSocket(host, port); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, + UnknownHostException { + return new SlowCloseSocket(host, port, localHost, localPort); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return new SlowCloseSocket(address, port, localAddress, localPort); + } + + } + @Override + protected SocketFactory createSocketFactory() throws IOException { + return new SlowCloseSocketFactory(); + } + + } + + TransportFactory.registerTransportFactory("tcp", new SlowCloseSocketTcpTransportFactory()); + + } + + public void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(URISupport.removeQuery(connector.getConnectUri()) + "?useKeepAlive=false&wireFormat.maxInactivityDuration=2000"); + } + + @Override + public void testCreateDurableConsumerCloseThenReconnect() throws Exception { + reconnectInExceptionListener = true; + makeConsumer(); + connection.setExceptionListener(this); + ((ActiveMQConnection)connection).addTransportListener(this); + assertTrue("inactive connection timedout", gotException.await(30, TimeUnit.SECONDS)); + assertNotNull("Got expected exception on close reconnect overlap: " + reconnectException, reconnectException); + } + + + public void testCreateDurableConsumerSlowCloseThenReconnectTransportListener() throws Exception { + reconnectInTransportListener = true; + makeConsumer(); + connection.setExceptionListener(this); + ((ActiveMQConnection)connection).addTransportListener(this); + assertTrue("inactive connection timedout", gotException.await(30, TimeUnit.SECONDS)); + assertNull("No exception: " + reconnectException, reconnectException); + } + + public void onException(JMSException exception) { + LOG.info("Exception listener exception:" + exception); + if (reconnectInExceptionListener) { + try { + makeConsumer(); + } catch (Exception e) { + reconnectException = e; + } + + gotException.countDown(); + } + } + + public void onCommand(Object command) {} + + public void onException(IOException error) { + LOG.info("Transport listener exception:" + error); + if (reconnectInTransportListener) { + try { + TimeUnit.MILLISECONDS.sleep(500); + makeConsumer(); + } catch (Exception e) { + reconnectException = e; + } + + gotException.countDown(); + } + } + + public void transportInterupted() {} + + public void transportResumed() {} +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableConsumerCloseAndReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableConsumerCloseAndReconnectTest.java new file mode 100644 index 0000000000..32c2d2c325 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableConsumerCloseAndReconnectTest.java @@ -0,0 +1,246 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.test.TestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * + */ +public class DurableConsumerCloseAndReconnectTest extends TestSupport { + protected static final long RECEIVE_TIMEOUT = 5000L; + private static final Logger LOG = LoggerFactory.getLogger(DurableConsumerCloseAndReconnectTest.class); + + BrokerService brokerService; + + protected Connection connection; + private Session session; + private MessageConsumer consumer; + private MessageProducer producer; + private Destination destination; + private int messageCount; + + private String vmConnectorURI; + + + @Override + protected void setUp() throws Exception { + createBroker(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + stopBroker(); + super.tearDown(); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(vmConnectorURI); + } + + protected void createBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setUseJmx(false); + brokerService.setPersistent(false); + KahaDBPersistenceAdapter store = new KahaDBPersistenceAdapter(); + brokerService.setPersistenceAdapter(store); + brokerService.start(); + brokerService.waitUntilStarted(); + vmConnectorURI = brokerService.getVmConnectorURI().toString(); + } + + protected void stopBroker() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + } + + public void testDurableSubscriberReconnectMultipleTimes() throws Exception { + Connection dummyConnection = createConnection(); + dummyConnection.start(); + + makeConsumer(Session.AUTO_ACKNOWLEDGE); + closeConsumer(); + + publish(30); + + int counter = 1; + for (int i = 0; i < 15; i++) { + makeConsumer(Session.AUTO_ACKNOWLEDGE); + Message message = consumer.receive(RECEIVE_TIMEOUT); + assertTrue("Should have received a message!", message != null); + LOG.info("Received message " + counter++); + message = consumer.receive(RECEIVE_TIMEOUT); + assertTrue("Should have received a message!", message != null); + LOG.info("Received message " + counter++); + closeConsumer(); + } + + dummyConnection.close(); + } + + public void testCreateDurableConsumerCloseThenReconnect() throws Exception { + // force the server to stay up across both connection tests + Connection dummyConnection = createConnection(); + dummyConnection.start(); + + consumeMessagesDeliveredWhileConsumerClosed(); + + dummyConnection.close(); + + // now lets try again without one connection open + consumeMessagesDeliveredWhileConsumerClosed(); + } + + protected void consumeMessagesDeliveredWhileConsumerClosed() throws Exception { + // default to client ack for consumer + makeConsumer(); + closeConsumer(); + + publish(1); + + // wait a few moments for the close to really occur + Thread.sleep(1000); + + makeConsumer(); + + Message message = consumer.receive(RECEIVE_TIMEOUT); + assertTrue("Should have received a message!", message != null); + + closeConsumer(); + + LOG.info("Now lets create the consumer again and because we didn't ack, we should get it again"); + makeConsumer(); + + message = consumer.receive(RECEIVE_TIMEOUT); + assertTrue("Should have received a message!", message != null); + message.acknowledge(); + + closeConsumer(); + + LOG.info("Now lets create the consumer again and because we did ack, we should not get it again"); + makeConsumer(); + + message = consumer.receive(2000); + assertTrue("Should have no more messages left!", message == null); + + closeConsumer(); + + LOG.info("Lets publish one more message now"); + publish(1); + + makeConsumer(); + message = consumer.receive(RECEIVE_TIMEOUT); + assertTrue("Should have received a message!", message != null); + message.acknowledge(); + + closeConsumer(); + } + + protected void publish(int numMessages) throws Exception { + connection = createConnection(); + connection.start(); + + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = createDestination(); + + producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + for (int i = 0; i < numMessages; i++) { + TextMessage msg = session.createTextMessage("This is a test: " + messageCount++); + producer.send(msg); + } + + producer.close(); + producer = null; + closeSession(); + } + + protected Destination createDestination() throws JMSException { + if (isTopic()) { + return session.createTopic(getSubject()); + } else { + return session.createQueue(getSubject()); + } + } + + protected boolean isTopic() { + return true; + } + + protected void closeConsumer() throws JMSException { + LOG.info("Closing the consumer"); + consumer.close(); + consumer = null; + closeSession(); + } + + protected void closeSession() throws JMSException { + session.close(); + session = null; + connection.close(); + connection = null; + } + + protected void makeConsumer() throws Exception { + makeConsumer(Session.CLIENT_ACKNOWLEDGE); + } + + protected void makeConsumer(int ackMode) throws Exception { + String durableName = getName(); + String clientID = getSubject(); + LOG.info("Creating a durable subscriber for clientID: " + clientID + " and durable name: " + durableName); + createSession(clientID, ackMode); + consumer = createConsumer(durableName); + } + + private MessageConsumer createConsumer(String durableName) throws JMSException { + if (destination instanceof Topic) { + return session.createDurableSubscriber((Topic)destination, durableName); + } else { + return session.createConsumer(destination); + } + } + + protected void createSession(String clientID, int ackMode) throws Exception { + connection = createConnection(); + connection.setClientID(clientID); + connection.start(); + + session = connection.createSession(false, ackMode); + destination = createDestination(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubDelayedUnsubscribeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubDelayedUnsubscribeTest.java new file mode 100644 index 0000000000..438e2643ed --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubDelayedUnsubscribeTest.java @@ -0,0 +1,780 @@ +/** + * 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 ONDITIONS 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.usecases; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Vector; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * A cut down version of DurableSubProcessWithRestartTest that focuses on kahaDB file retention + */ +public class DurableSubDelayedUnsubscribeTest { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubDelayedUnsubscribeTest.class); + + private static final long RUNTIME = 2 * 60 * 1000; + private static final int CARGO_SIZE = 400; // max + private static final int MAX_CLIENTS = 15; + private static boolean ALLOW_SUBSCRIPTION_ABANDONMENT = true; + private static final Vector exceptions = new Vector(); + + private BrokerService broker; + private ActiveMQTopic topic; + + private ClientManager clientManager; + private Server server; + private HouseKeeper houseKeeper; + + private final ReentrantReadWriteLock processLock = new ReentrantReadWriteLock(true); + + @Test + public void testProcess() throws Exception { + + server.start(); + clientManager.start(); + + houseKeeper.start(); + + // Sleep to + Thread.sleep(RUNTIME); + + // inform message producer to stop + server.stopped = true; + + // add one Subscriber to the topic that will not be unsubscribed. + // should not have any pending messages in the kahadb store + Client lastClient = new Client(32000, ClientType.A); + lastClient.process(1000); + + // stop client manager from creating any more clients + clientManager.stopped = true; + + final BrokerService brokerService = this.broker; + + // Wait for all client subscription to be unsubscribed or swept away. + // Ensure we sleep longer than the housekeeper's sweep delay otherwise we can + // miss the fact that all durables that were abandoned do finally get cleaned up. + + // Wait for all clients to stop + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return clientManager.getClientCount() == 0; + } + }, Client.lifetime + TimeUnit.SECONDS.toMillis(10)); + + assertTrue("should have only one inactiveSubscriber subscribed but was: " + brokerService.getAdminView().getInactiveDurableTopicSubscribers().length, + Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return brokerService.getAdminView().getInactiveDurableTopicSubscribers().length == 1; + } + }, houseKeeper.SWEEP_DELAY * 2)); + + assertTrue("should be no subscribers subscribed but was: " + brokerService.getAdminView().getDurableTopicSubscribers().length, + Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return brokerService.getAdminView().getDurableTopicSubscribers().length == 0; + } + }, TimeUnit.MINUTES.toMillis(3))); + + processLock.writeLock().lock(); + + // check outcome. + + ObjectName[] subscribers = broker.getAdminView().getDurableTopicSubscribers(); + ObjectName[] inactiveSubscribers = broker.getAdminView().getInactiveDurableTopicSubscribers(); + final KahaDBPersistenceAdapter persistenceAdapter = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + + printDebugClientInfo(subscribers, inactiveSubscribers, persistenceAdapter); + + assertEquals("should have only one inactiveSubscriber subscribed", 1, broker.getAdminView().getInactiveDurableTopicSubscribers().length); + assertEquals("should be no subscribers subscribed", 0, broker.getAdminView().getDurableTopicSubscribers().length); + + final KahaDBPersistenceAdapter pa = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + assertTrue("should be less than 3 journal file left but was: " + persistenceAdapter.getStore().getJournal().getFileMap().size(), + Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return pa.getStore().getJournal().getFileMap().size() <= 3; + } + }, TimeUnit.MINUTES.toMillis(3))); + + // Be good and cleanup our mess a bit. + this.houseKeeper.shutdown(); + + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + + LOG.info("DONE."); + } + + private void printDebugClientInfo(ObjectName[] subscribers, ObjectName[] inactiveSubscribers, final KahaDBPersistenceAdapter pa) throws IOException { + + LOG.info("====>>> START DEBUG Subscriber INFO"); + + LOG.info("Number of subscribers subscribed as seen through JMX is" + subscribers.length); + + for (int i = 0; i < subscribers.length; i++) { + LOG.info("subscribers subscribed as seen throngh JMX: " + subscribers[i]); + } + + LOG.info("Number of inactiveSubscribers subscribed as seen through JMX is" + inactiveSubscribers.length); + + for (int i = 0; i < inactiveSubscribers.length; i++) { + LOG.info("subscribers subscribed as seen throngh JMX: " + inactiveSubscribers[i]); + } + + LOG.info("ClientManager.clients size is" + clientManager.clients.size()); + + for (int i = 0; i < clientManager.clients.size(); i++) { + LOG.info("clients is: " + clientManager.clients.get(i)); + } + + LOG.info("housekeep.subscriptions size is " + houseKeeper.abandonedSubscriptions.size()); + + for (int i = 0; i < houseKeeper.abandonedSubscriptions.size(); i++) { + LOG.info("housekeep is: " + houseKeeper.abandonedSubscriptions.get(i)); + } + + LOG.info("number of journal files left" + pa.getStore().getJournal().getFileMap().size()); + + LOG.info("====>>> END DEBUG Subscriber INFO"); + } + + /** + * Creates batch of messages in a transaction periodically. The last message + * in the transaction is always a special message what contains info about + * the whole transaction. + *

+ * Notifies the clients about the created messages also. + */ + final class Server extends Thread { + + public boolean stopped; + final String url = "vm://" + DurableSubDelayedUnsubscribeTest.getName() + "?" + + "jms.redeliveryPolicy.maximumRedeliveries=2&jms.redeliveryPolicy.initialRedeliveryDelay=500&" + + "jms.producerWindowSize=20971520&jms.prefetchPolicy.all=100&" + "jms.copyMessageOnSend=false&jms.disableTimeStampsByDefault=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=false&" + "jms.watchTopicAdvisories=false&" + "waitForStart=200&create=false"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + final Object sendMutex = new Object(); + final String[] cargos = new String[500]; + + int transRover = 0; + int messageRover = 0; + + public Server() { + super("Server"); + setDaemon(true); + } + + @Override + public void run() { + try { + while (true) { + + if (stopped) { + // server should stop producing + break; + } + + Thread.sleep(500); + processLock.readLock().lock(); + try { + send(); + } finally { + processLock.readLock().unlock(); + } + } + } catch (Throwable e) { + exit("Server.run failed", e); + } + } + + public void send() throws JMSException { + // do not create new clients now + // ToDo: Test this case later. + synchronized (sendMutex) { + int trans = ++transRover; + boolean relevantTrans = random(2) > 1; + ClientType clientType = relevantTrans ? ClientType.randomClientType() : null; // sends + // this + // types + int count = random(200); + + LOG.info("Sending Trans[id=" + trans + ", count=" + count + ", clientType=" + clientType + "]"); + + Connection con = cf.createConnection(); + Session sess = con.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer prod = sess.createProducer(null); + + for (int i = 0; i < count; i++) { + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + String type = clientType != null ? clientType.randomMessageType() : ClientType.randomNonRelevantMessageType(); + message.setStringProperty("TYPE", type); + + if (CARGO_SIZE > 0) + message.setStringProperty("CARGO", getCargo(random(CARGO_SIZE))); + + prod.send(topic, message); + + } + + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("COMMIT", true); + message.setBooleanProperty("RELEVANT", relevantTrans); + prod.send(topic, message); + + sess.commit(); + LOG.info("Committed Trans[id=" + trans + ", count=" + count + ", clientType=" + clientType + "], ID=" + messageRover); + + sess.close(); + con.close(); + } + } + + private String getCargo(int length) { + if (length == 0) + return null; + + if (length < cargos.length) { + String result = cargos[length]; + if (result == null) { + result = getCargoImpl(length); + cargos[length] = result; + } + return result; + } + return getCargoImpl(length); + } + + private String getCargoImpl(int length) { + StringBuilder sb = new StringBuilder(length); + for (int i = length; --i >= 0;) { + sb.append('a'); + } + return sb.toString(); + } + } + + /** + * Clients listen on different messages in the topic. The 'TYPE' property + * helps the client to select the proper messages. + */ + private enum ClientType { + A("a", "b", "c"), B("c", "d", "e"), C("d", "e", "f"), D("g", "h"); + + public final String[] messageTypes; + + public final String selector; + + ClientType(String... messageTypes) { + this.messageTypes = messageTypes; + + StringBuilder sb = new StringBuilder("TYPE in ("); + for (int i = 0; i < messageTypes.length; i++) { + if (i > 0) + sb.append(", "); + sb.append('\'').append(messageTypes[i]).append('\''); + } + sb.append(')'); + selector = sb.toString(); + } + + public static ClientType randomClientType() { + return values()[DurableSubDelayedUnsubscribeTest.random(values().length - 1)]; + } + + public final String randomMessageType() { + return messageTypes[DurableSubDelayedUnsubscribeTest.random(messageTypes.length - 1)]; + } + + public static String randomNonRelevantMessageType() { + return Integer.toString(DurableSubDelayedUnsubscribeTest.random(20)); + } + + @Override + public final String toString() { + return this.name() /* + '[' + selector + ']' */; + } + } + + /** + * Creates new cliens. + */ + private final class ClientManager extends Thread { + + private int clientRover = 0; + + private final CopyOnWriteArrayList clients = new CopyOnWriteArrayList(); + + private boolean stopped; + + public ClientManager() { + super("ClientManager"); + setDaemon(true); + } + + public int getClientCount() { + return clients.size(); + } + + @Override + public void run() { + try { + while (true) { + if (clients.size() < MAX_CLIENTS) { + + if (stopped) { + // get out, don't start any more threads + break; + } + processLock.readLock().lock(); + try { + createNewClient(); + } finally { + processLock.readLock().unlock(); + } + } + + int size = clients.size(); + sleepRandom(size * 3 * 1000, size * 6 * 1000); + } + } catch (Throwable e) { + exit("ClientManager.run failed.", e); + } + } + + private void createNewClient() throws JMSException { + ClientType type = ClientType.randomClientType(); + + Client client; + synchronized (server.sendMutex) { + client = new Client(++clientRover, type); + clients.add(client); + } + client.start(); + + LOG.info(client.toString() + " created. " + this); + } + + public void removeClient(Client client) { + clients.remove(client); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ClientManager[count="); + sb.append(clients.size()); + sb.append(", clients="); + boolean sep = false; + for (Client client : clients) { + if (sep) + sb.append(", "); + else + sep = true; + sb.append(client.toString()); + } + sb.append(']'); + return sb.toString(); + } + } + + /** + * Consumes massages from a durable subscription. Goes online/offline + * periodically. Checks the incoming messages against the sent messages of + * the server. + */ + private final class Client extends Thread { + + String url = "failover:(tcp://localhost:61656?wireFormat.maxInactivityDuration=0)?" + "jms.watchTopicAdvisories=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=true&" + "jms.producerWindowSize=20971520&" + "jms.copyMessageOnSend=false&" + + "initialReconnectDelay=100&maxReconnectDelay=30000&" + "useExponentialBackOff=true"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + public static final String SUBSCRIPTION_NAME = "subscription"; + + private final int id; + private final String conClientId; + + public static final int lifetime = 60 * 1000; + private final int online = 1 * 1000; + private final int offline = 59 * 1000; + + private final ClientType clientType; + private final String selector; + + public Client(int id, ClientType clientType) throws JMSException { + super("Client" + id); + setDaemon(true); + + this.id = id; + conClientId = "cli" + id; + this.clientType = clientType; + selector = "(COMMIT = true and RELEVANT = true) or " + clientType.selector; + + subscribe(); + } + + @Override + public void run() { + // long end = System.currentTimeMillis() + lifetime.next(); + long end = System.currentTimeMillis() + lifetime; + try { + boolean sleep = false; + while (true) { + long max = end - System.currentTimeMillis(); + if (max <= 0) + break; + + if (sleep) + Thread.sleep(offline); + // offline.sleepRandom(); + else + sleep = true; + + processLock.readLock().lock(); + try { + process(online); + } finally { + processLock.readLock().unlock(); + } + } + + // 50% unsubscribe, 50% abondon subscription + if (!ALLOW_SUBSCRIPTION_ABANDONMENT) { + unsubscribe(); + ALLOW_SUBSCRIPTION_ABANDONMENT = true; + } else { + + LOG.info("Client abandon the subscription. " + this); + + // housekeeper should sweep these abandoned subscriptions + houseKeeper.abandonedSubscriptions.add(conClientId); + ALLOW_SUBSCRIPTION_ABANDONMENT = false; + } + } catch (Throwable e) { + exit(toString() + " failed.", e); + } + + clientManager.removeClient(this); + LOG.info(toString() + " DONE."); + } + + private void process(long processingTime) throws JMSException { + long end = System.currentTimeMillis() + processingTime; + long hardEnd = end + 20000; // wait to finish the transaction. + boolean inTransaction = false; + int transCount = 0; + + LOG.info(toString() + " ONLINE."); + Connection con = openConnection(); + Session sess = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = sess.createDurableSubscriber(topic, SUBSCRIPTION_NAME, selector, false); + try { + do { + long max = end - System.currentTimeMillis(); + if (max <= 0) { + if (!inTransaction) + break; + + max = hardEnd - System.currentTimeMillis(); + if (max <= 0) + exit("" + this + " failed: Transaction is not finished."); + } + + Message message = consumer.receive(max); + if (message == null) + continue; + + if (message.propertyExists("COMMIT")) { + message.acknowledge(); // CLIENT_ACKNOWLEDGE + + LOG.info("Received Trans[id=" + message.getIntProperty("TRANS") + ", count=" + transCount + "] in " + this + "."); + + inTransaction = false; + transCount = 0; + } else { + inTransaction = true; + transCount++; + } + } while (true); + } finally { + sess.close(); + con.close(); + LOG.info(toString() + " OFFLINE."); + } + } + + private Connection openConnection() throws JMSException { + Connection con = cf.createConnection(); + con.setClientID(conClientId); + con.start(); + return con; + } + + private void subscribe() throws JMSException { + Connection con = openConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, SUBSCRIPTION_NAME, selector, true); + session.close(); + con.close(); + } + + private void unsubscribe() throws JMSException { + Connection con = openConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe(SUBSCRIPTION_NAME); + session.close(); + con.close(); + } + + @Override + public String toString() { + return "Client[id=" + id + ", type=" + clientType + "]"; + } + } + + /** + * Sweeps out not-used durable subscriptions. + */ + private final class HouseKeeper extends Thread { + + private final AtomicBoolean done = new AtomicBoolean(); + + public final long SWEEP_DELAY = TimeUnit.MINUTES.toMillis(3); + + private HouseKeeper() { + super("HouseKeeper"); + setDaemon(true); + } + + public final CopyOnWriteArrayList abandonedSubscriptions = new CopyOnWriteArrayList(); + + public void shutdown() throws Exception { + done.set(true); + + // In case we are sleeping, abort the sleep. + this.interrupt(); + + // Wait for run to complete. + this.join(TimeUnit.MINUTES.toMillis(SWEEP_DELAY)); + + // Ensure all abandoned subscriptions get wiped. + if (!abandonedSubscriptions.isEmpty()) { + this.sweep(); + } + } + + @Override + public void run() { + while (!done.get()) { + try { + Thread.sleep(SWEEP_DELAY); + + processLock.readLock().lock(); + try { + sweep(); + } finally { + processLock.readLock().unlock(); + } + } catch (InterruptedException ex) { + break; + } catch (Throwable e) { + Exception log = new Exception("HouseKeeper failed.", e); + log.printStackTrace(); + } + } + } + + private void sweep() throws Exception { + LOG.info("Housekeeper sweeping."); + + int closed = 0; + ArrayList sweeped = new ArrayList(); + try { + for (String clientId : abandonedSubscriptions) { + LOG.info("Sweeping out subscription of " + clientId + "."); + broker.getAdminView().destroyDurableSubscriber(clientId, Client.SUBSCRIPTION_NAME); + sweeped.add(clientId); + closed++; + } + } catch (Exception ignored) { + LOG.info("Ex on destroy sub " + ignored); + } finally { + abandonedSubscriptions.removeAll(sweeped); + } + + LOG.info("Housekeeper sweeped out " + closed + " subscriptions."); + } + } + + public static int random(int max) { + return (int) (Math.random() * (max + 1)); + } + + public static int random(int min, int max) { + return random(max - min) + min; + } + + public static void sleepRandom(int maxMillis) throws InterruptedException { + Thread.sleep(random(maxMillis)); + } + + public static void sleepRandom(int minMillis, int maxMillis) throws InterruptedException { + Thread.sleep(random(minMillis, maxMillis)); + } + + public static final class Random { + + final int min; + final int max; + + Random(int min, int max) { + this.min = min; + this.max = max; + } + + public int next() { + return random(min, max); + } + + public void sleepRandom() throws InterruptedException { + DurableSubDelayedUnsubscribeTest.sleepRandom(min, max); + } + } + + public static void exit(String message) { + exit(message, null); + } + + public static void exit(String message, Throwable e) { + Throwable cause = new RuntimeException(message, e); + LOG.error(message, cause); + exceptions.add(cause); + fail(cause.toString()); + } + + @Before + public void setUp() throws Exception { + topic = new ActiveMQTopic("TopicT"); + startBroker(); + + clientManager = new ClientManager(); + server = new Server(); + houseKeeper = new HouseKeeper(); + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + private void startBroker() throws Exception { + startBroker(true); + } + + private void startBroker(boolean deleteAllMessages) throws Exception { + if (broker != null) + return; + + broker = BrokerFactory.createBroker("broker:(vm://" + getName() + ")"); + broker.setBrokerName(getName()); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + + File kahadbData = new File("activemq-data/" + getName() + "-kahadb"); + if (deleteAllMessages) + delete(kahadbData); + + broker.setPersistent(true); + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setDirectory(kahadbData); + kahadb.setJournalMaxFileLength(512 * 1024); + broker.setPersistenceAdapter(kahadb); + + broker.addConnector("tcp://localhost:61656"); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getTempUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getStoreUsage().setLimit(256 * 1024 * 1024); + + broker.start(); + } + + protected static String getName() { + return "DurableSubProcessWithRestartTest"; + } + + private static boolean delete(File path) { + if (path == null) + return true; + + if (path.isDirectory()) { + for (File file : path.listFiles()) { + delete(file); + } + } + return path.delete(); + } + + private void destroyBroker() throws Exception { + if (broker == null) + return; + + broker.stop(); + broker = null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubInBrokerNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubInBrokerNetworkTest.java new file mode 100644 index 0000000000..cad4170b2b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubInBrokerNetworkTest.java @@ -0,0 +1,187 @@ +/** + * 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.usecases; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.network.NetworkTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tests durable topic subscriptions inside a network of brokers. + * + * @author tmielke + * + */ +public class DurableSubInBrokerNetworkTest extends NetworkTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubInBrokerNetworkTest.class); + // protected BrokerService localBroker; + private final String subName = "Subscriber1"; + private final String subName2 = "Subscriber2"; + private final String topicName = "TEST.FOO"; + + protected void setUp() throws Exception { + useJmx=true; + super.setUp(); + + URI ncUri = new URI("static:(" + connector.getConnectUri().toString() + ")"); + NetworkConnector nc = new DiscoveryNetworkConnector(ncUri); + nc.setDuplex(true); + remoteBroker.addNetworkConnector(nc); + nc.start(); + } + + protected void tearDown() throws Exception { + if (remoteBroker.isStarted()) { + remoteBroker.stop(); + remoteBroker.waitUntilStopped(); + } + if (broker.isStarted()) { + broker.stop(); + broker.waitUntilStopped(); + } + super.tearDown(); + } + + + /** + * Creates a durable topic subscription, checks that it is propagated + * in the broker network, removes the subscription and checks that + * the subscription is removed from remote broker as well. + * + * @throws Exception + */ + public void testDurableSubNetwork() throws Exception { + LOG.info("testDurableSubNetwork started."); + + // create durable sub + ActiveMQConnectionFactory fact = new ActiveMQConnectionFactory(connector.getConnectUri().toString()); + Connection conn = fact.createConnection(); + conn.setClientID("clientID1"); + Session session = conn.createSession(false, 1); + Destination dest = session.createTopic(topicName); + TopicSubscriber sub = session.createDurableSubscriber((Topic)dest, subName); + LOG.info("Durable subscription of name " + subName + "created."); + Thread.sleep(100); + + // query durable sub on local and remote broker + // raise an error if not found + + assertTrue(foundSubInLocalBroker(subName)); + + + assertTrue(foundSubInRemoteBrokerByTopicName(topicName)); + + // unsubscribe from durable sub + sub.close(); + session.unsubscribe(subName); + LOG.info("Unsubscribed from durable subscription."); + Thread.sleep(100); + + // query durable sub on local and remote broker + // raise an error if its not removed from both brokers + assertFalse(foundSubInLocalBroker(subName)); + + assertFalse("Durable subscription not unregistered on remote broker", + foundSubInRemoteBrokerByTopicName(topicName)); + + + } + + public void testTwoDurableSubsInNetworkWithUnsubscribe() throws Exception{ + + // create 1st durable sub to topic TEST.FOO + ActiveMQConnectionFactory fact = new ActiveMQConnectionFactory(connector.getConnectUri().toString()); + Connection conn = fact.createConnection(); + conn.setClientID("clientID1"); + Session session = conn.createSession(false, 1); + Destination dest = session.createTopic(topicName); + TopicSubscriber sub = session.createDurableSubscriber((Topic)dest, subName); + LOG.info("Durable subscription of name " + subName + "created."); + TopicSubscriber sub2 = session.createDurableSubscriber((Topic) dest, subName2); + LOG.info("Durable subscription of name " + subName2 + "created."); + + Thread.sleep(100); + + // query durable sub on local and remote broker + // raise an error if not found + + assertTrue(foundSubInLocalBroker(subName)); + assertTrue(foundSubInLocalBroker(subName2)); + + + assertTrue(foundSubInRemoteBrokerByTopicName(topicName)); + + // unsubscribe from durable sub + sub.close(); + session.unsubscribe(subName); + LOG.info("Unsubscribed from durable subscription."); + Thread.sleep(100); + + // query durable sub on local and remote broker + assertFalse(foundSubInLocalBroker(subName)); + assertTrue(foundSubInLocalBroker(subName2)); + + assertTrue("Durable subscription should still be on remote broker", + foundSubInRemoteBrokerByTopicName(topicName)); + + sub2.close(); + session.unsubscribe(subName2); + + Thread.sleep(100); + + assertFalse(foundSubInLocalBroker(subName2)); + + assertFalse("Durable subscription not unregistered on remote broker", + foundSubInRemoteBrokerByTopicName(topicName)); + + } + + private boolean foundSubInRemoteBrokerByTopicName(String topicName) throws Exception { + boolean foundSub = false; + ObjectName[] subs = remoteBroker.getAdminView().getDurableTopicSubscribers(); + for (int i=0 ; i exceptions = new Vector(); + + // long form of test that found https://issues.apache.org/jira/browse/AMQ-3805 + @Ignore ("short version in org.apache.activemq.usecases.DurableSubscriptionOfflineTest.testNoDuplicateOnConcurrentSendTranCommitAndActivate" + + " and org.apache.activemq.usecases.DurableSubscriptionOfflineTest.testOrderOnActivateDeactivate") + @Test + public void testProcess() { + try { + server.start(); + clientManager.start(); + + if (ALLOW_SUBSCRIPTION_ABANDONMENT) + houseKeeper.start(); + + if (BROKER_RESTART <= 0) + Thread.sleep(RUNTIME); + else { + long end = System.currentTimeMillis() + RUNTIME; + + while (true) { + long now = System.currentTimeMillis(); + if (now > end) + break; + + now = end - now; + now = now < BROKER_RESTART ? now : BROKER_RESTART; + Thread.sleep(now); + + restartBroker(); + } + } + } catch (Throwable e) { + exit("ProcessTest.testProcess failed.", e); + } + + //allow the clients to unsubscribe before finishing + clientManager.setEnd(true); + try { + Thread.sleep(60 * 1000); + } catch (InterruptedException e) { + exit("ProcessTest.testProcess failed.", e); + } + + server.done = true; + + try { + server.join(60*1000); + } catch (Exception ignored) {} + processLock.writeLock().lock(); + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + LOG.info("DONE."); + } + + private void restartBroker() throws Exception { + LOG.info("Broker restart: waiting for components."); + + processLock.writeLock().lock(); + try { + destroyBroker(); + startBroker(false); + + restartCount++; + LOG.info("Broker restarted. count: " + restartCount); + } finally { + processLock.writeLock().unlock(); + } + } + + /** + * Creates batch of messages in a transaction periodically. The last message + * in the transaction is always a special message what contains info about + * the whole transaction. + *

+ * Notifies the clients about the created messages also. + */ + final class Server extends Thread { + + final String url = "vm://" + + DurableSubProcessConcurrentCommitActivateNoDuplicateTest.getName() + + "?" + + "jms.redeliveryPolicy.maximumRedeliveries=2&jms.redeliveryPolicy.initialRedeliveryDelay=500&" + + "jms.producerWindowSize=20971520&jms.prefetchPolicy.all=100&" + + "jms.copyMessageOnSend=false&jms.disableTimeStampsByDefault=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=false&" + + "jms.watchTopicAdvisories=false&" + + "waitForStart=200&create=false"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + final Object sendMutex = new Object(); + final String[] cargos = new String[500]; + + int transRover = 0; + int messageRover = 0; + public volatile int committingTransaction = -1; + public boolean done = false; + public Server() { + super("Server"); + setPriority(Thread.MIN_PRIORITY); + setDaemon(true); + } + + @Override + public void run() { + try { + while (!done) { + + Thread.sleep(1000); + + processLock.readLock().lock(); + try { + send(); + } finally { + processLock.readLock().unlock(); + } + } + } catch (Throwable e) { + exit("Server.run failed", e); + } + } + + public void send() throws JMSException { + // do not create new clients now + // ToDo: Test this case later. + synchronized (sendMutex) { + int trans = ++transRover; + boolean relevantTrans = true; //random(2) > 1; + ClientType clientType = relevantTrans ? ClientType + .randomClientType() : null; // sends this types + //int count = random(500, 700); + int count = 1000; + + LOG.info("Sending Trans[id=" + trans + ", count=" + + count + ", clientType=" + clientType + ", firstID=" + (messageRover+1) + "]"); + + Connection con = cf.createConnection(); + Session sess = con + .createSession(true, Session.SESSION_TRANSACTED); + MessageProducer prod = sess.createProducer(null); + + for (int i = 0; i < count; i++) { + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + String type = clientType != null ? clientType + .randomMessageType() : ClientType + .randomNonRelevantMessageType(); + message.setStringProperty("TYPE", type); + + if (CARGO_SIZE > 0) + message.setStringProperty("CARGO", + getCargo(random(CARGO_SIZE))); + + prod.send(topic, message); + clientManager.onServerMessage(message); + } + + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("COMMIT", true); + message.setBooleanProperty("RELEVANT", relevantTrans); + prod.send(topic, message); + clientManager.onServerMessage(message); + + committingTransaction = trans; + sess.commit(); + committingTransaction = -1; + + LOG.info("Committed Trans[id=" + trans + ", count=" + + count + ", clientType=" + clientType + "], ID=" + messageRover); + + sess.close(); + con.close(); + } + } + + private String getCargo(int length) { + if (length == 0) + return null; + + if (length < cargos.length) { + String result = cargos[length]; + if (result == null) { + result = getCargoImpl(length); + cargos[length] = result; + } + return result; + } + return getCargoImpl(length); + } + + private String getCargoImpl(int length) { + StringBuilder sb = new StringBuilder(length); + for (int i = length; --i >= 0;) { + sb.append('a'); + } + return sb.toString(); + } + } + + /** + * Clients listen on different messages in the topic. The 'TYPE' property + * helps the client to select the proper messages. + */ + private enum ClientType { + A("a", "b", "c"), B("c", "d", "e"), C("d", "e", "f"), D("g", "h"); + + public final String[] messageTypes; + public final HashSet messageTypeSet; + public final String selector; + + ClientType(String... messageTypes) { + this.messageTypes = messageTypes; + messageTypeSet = new HashSet(Arrays.asList(messageTypes)); + + StringBuilder sb = new StringBuilder("TYPE in ("); + for (int i = 0; i < messageTypes.length; i++) { + if (i > 0) + sb.append(", "); + sb.append('\'').append(messageTypes[i]).append('\''); + } + sb.append(')'); + selector = sb.toString(); + } + + public static ClientType randomClientType() { + return values()[DurableSubProcessConcurrentCommitActivateNoDuplicateTest + .random(values().length - 1)]; + } + + public final String randomMessageType() { + return messageTypes[DurableSubProcessConcurrentCommitActivateNoDuplicateTest + .random(messageTypes.length - 1)]; + } + + public static String randomNonRelevantMessageType() { + return Integer + .toString(DurableSubProcessConcurrentCommitActivateNoDuplicateTest.random(20)); + } + + public final boolean isRelevant(String messageType) { + return messageTypeSet.contains(messageType); + } + + @Override + public final String toString() { + return this.name() /* + '[' + selector + ']' */; + } + } + + /** + * Creates new cliens. + */ + private final class ClientManager extends Thread { + + private int clientRover = 0; + + private final CopyOnWriteArrayList clients = new CopyOnWriteArrayList(); + + private boolean end; + + public ClientManager() { + super("ClientManager"); + setDaemon(true); + } + + public synchronized void setEnd(boolean end) { + this.end = end; + + } + + @Override + public void run() { + try { + while (true) { + if (clients.size() < MAX_CLIENTS && !end) { + processLock.readLock().lock(); + try { + createNewClient(); + } finally { + processLock.readLock().unlock(); + } + } + + int size = clients.size(); + //sleepRandom(1000, 4000); + Thread.sleep(100); + } + } catch (Throwable e) { + exit("ClientManager.run failed.", e); + } + } + + private void createNewClient() throws JMSException { + ClientType type = ClientType.randomClientType(); + + Client client; + synchronized (server.sendMutex) { + client = new Client(++clientRover, type, CLIENT_LIFETIME, + CLIENT_ONLINE, CLIENT_OFFLINE); + clients.add(client); + } + client.start(); + + LOG.info(client.toString() + " created. " + this); + } + + public void removeClient(Client client) { + clients.remove(client); + } + + public void onServerMessage(Message message) throws JMSException { + for (Client client : clients) { + client.onServerMessage(message); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ClientManager[count="); + sb.append(clients.size()); + sb.append(", clients="); + boolean sep = false; + for (Client client : clients) { + if (sep) + sb.append(", "); + else + sep = true; + sb.append(client.toString()); + } + sb.append(']'); + return sb.toString(); + } + } + + /** + * Consumes massages from a durable subscription. Goes online/offline + * periodically. Checks the incoming messages against the sent messages of + * the server. + */ + private final class Client extends Thread { + + String url = "failover:(tcp://localhost:61656?wireFormat.maxInactivityDuration=0)?" + + "jms.watchTopicAdvisories=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=true&" + + "jms.producerWindowSize=20971520&" + + "jms.copyMessageOnSend=false&" + + "jms.sendAcksAsync=false&" + + "initialReconnectDelay=100&maxReconnectDelay=30000&" + + "useExponentialBackOff=true"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + public static final String SUBSCRIPTION_NAME = "subscription"; + + private final int id; + private final String conClientId; + + private final Random lifetime; + private final Random online; + private final Random offline; + + private final ClientType clientType; + private final String selector; + + private final ConcurrentLinkedQueue waitingList = new ConcurrentLinkedQueue(); + private final HashSet processed = CHECK_REDELIVERY ? new HashSet( + 10000) : null; + + private ActiveMQMessageConsumer consumer = null; + + public Client(int id, ClientType clientType, Random lifetime, + Random online, Random offline) throws JMSException { + super("Client" + id); + setDaemon(true); + + this.id = id; + conClientId = "cli" + id; + this.clientType = clientType; + selector = "(COMMIT = true and RELEVANT = true) or " + + clientType.selector; + + this.lifetime = lifetime; + this.online = online; + this.offline = offline; + + subscribe(); + } + + @Override + public void run() { + long end = System.currentTimeMillis() + 60000; + try { + boolean sleep = false; + while (true) { + long max = end - System.currentTimeMillis(); + if (max <= 0) + break; + + /* + if (sleep) + offline.sleepRandom(); + else + sleep = true; + */ + + Thread.sleep(100); + + processLock.readLock().lock(); + onlineCount.incrementAndGet(); + try { + process(online.next()); + } finally { + onlineCount.decrementAndGet(); + processLock.readLock().unlock(); + } + } + + if (!ALLOW_SUBSCRIPTION_ABANDONMENT || random(1) > 0) + unsubscribe(); + else { + LOG.info("Client abandon the subscription. " + + this); + + // housekeeper should sweep these abandoned subscriptions + houseKeeper.abandonedSubscriptions.add(conClientId); + } + } catch (Throwable e) { + exit(toString() + " failed.", e); + } + + clientManager.removeClient(this); + LOG.info(toString() + " DONE."); + } + + private void process(long millis) throws JMSException { + //long end = System.currentTimeMillis() + millis; + long end = System.currentTimeMillis() + 200; + long hardEnd = end + 20000; // wait to finish the transaction. + boolean inTransaction = false; + int transCount = 0; + + Connection con = openConnection(); + Session sess = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + consumer = (ActiveMQMessageConsumer) sess.createDurableSubscriber(topic, + SUBSCRIPTION_NAME, selector, false); + LOG.info(toString() + " ONLINE."); + try { + do { + long max = end - System.currentTimeMillis(); + if (max <= 0) { + if (!inTransaction) { + LOG.info(toString() + " done after no work!"); + break; + } + + max = hardEnd - System.currentTimeMillis(); + if (max <= 0) + exit("" + this + + " failed: Transaction is not finished."); + } + + Message message = consumer.receive(max); + if (message == null) + continue; + + onClientMessage(message); + + if (message.propertyExists("COMMIT")) { + message.acknowledge(); // CLIENT_ACKNOWLEDGE + + int trans = message.getIntProperty("TRANS"); + LOG.info("Received Trans[id=" + + trans + ", count=" + + transCount + "] in " + this + "."); + + inTransaction = false; + transCount = 0; + + int committing = server.committingTransaction; + if (committing == trans) { + LOG.info("Going offline during transaction commit. messageID=" + message.getIntProperty("ID")); + break; + } + } else { + inTransaction = true; + transCount++; + if (1 == transCount) { + LOG.info("In Trans[id=" + message.getIntProperty("TRANS") + "] first ID=" + message.getIntProperty("ID")); + } + } + } while (true); + } finally { + sess.close(); + con.close(); + + LOG.info(toString() + " OFFLINE."); + + // Check if the messages are in the waiting + // list for long time. + Message topMessage = waitingList.peek(); + if (topMessage != null) + checkDeliveryTime(topMessage); + } + } + + public void onServerMessage(Message message) throws JMSException { + if (Boolean.TRUE.equals(message.getObjectProperty("COMMIT"))) { + if (Boolean.TRUE.equals(message.getObjectProperty("RELEVANT"))) + waitingList.add(message); + } else { + String messageType = message.getStringProperty("TYPE"); + if (clientType.isRelevant(messageType)) + waitingList.add(message); + } + } + + public void onClientMessage(Message message) { + Message serverMessage = waitingList.poll(); + try { + Integer receivedId = (Integer) message.getObjectProperty("ID"); + if (processed != null && processed.contains(receivedId)) + LOG.info("! Message has been processed before. " + + this + " redeliveredFlag=" + message.getJMSRedelivered() + ", message = " + message); + + if (serverMessage == null) + exit("" + + this + + " failed: There is no next server message, but received: " + + message); + + Integer serverId = (Integer) serverMessage + .getObjectProperty("ID"); + if (receivedId == null || serverId == null) + exit("" + this + " failed: message ID not found.\r\n" + + " received: " + message + "\r\n" + " server: " + + serverMessage); + + if (!serverId.equals(receivedId)) { + StringBuilder missingList = new StringBuilder(); + Object lastTrans = null; + int transCount = 0; + Message nextServerMessage = serverMessage; + do { + Integer nextServerId = (Integer) nextServerMessage.getObjectProperty("ID"); + if (nextServerId.equals(receivedId)) { + if (lastTrans != null) + missingList.append("Missing TRANS=").append(lastTrans).append(", size=").append(transCount).append("\r\n"); + break; + } + + Object trans = nextServerMessage.getObjectProperty("TRANS"); + if (!trans.equals(lastTrans)) { + if (lastTrans != null) + missingList.append("Missing TRANS=").append(lastTrans).append(", size=").append(transCount).append("\r\n"); + lastTrans = trans; + transCount = 1; + } + else + transCount++; + } while ((nextServerMessage = waitingList.poll()) != null); + + exit("Missing messages!\r\n" + missingList + + "Received message: " + message + "\r\n" + + "Expected message: " + serverMessage); + } + + checkDeliveryTime(message); + + if (processed != null) + processed.add(receivedId); + } catch (Throwable e) { + exit("" + this + ".onClientMessage failed.\r\n" + " received: " + + message + "\r\n" + " server: " + serverMessage, e); + } + } + + /** + * Checks if the message was not delivered fast enough. + */ + public void checkDeliveryTime(Message message) throws JMSException { + long creation = message.getJMSTimestamp(); + long min = System.currentTimeMillis() - (offline.max + online.min) + * (BROKER_RESTART > 0 ? 4 : 1); + + if (false && min > creation) { + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS"); + exit("" + this + ".checkDeliveryTime failed. Message time: " + + df.format(new Date(creation)) + ", min: " + + df.format(new Date(min)) + "\r\n" + message); + } + } + + private Connection openConnection() throws JMSException { + Connection con = cf.createConnection(); + con.setClientID(conClientId); + ((ActiveMQConnection) con).setCloseTimeout(60000); + con.start(); + return con; + } + + private void subscribe() throws JMSException { + processLock.readLock().lock(); + try { + Connection con = openConnection(); + Session session = con + .createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, SUBSCRIPTION_NAME, selector, + true); + session.close(); + con.close(); + } + finally { + processLock.readLock().unlock(); + } + } + + private void unsubscribe() throws JMSException { + processLock.readLock().lock(); + LOG.info("Unsubscribe: " + this); + try { + Connection con = openConnection(); + Session session = con + .createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe(SUBSCRIPTION_NAME); + session.close(); + con.close(); + } + finally { + processLock.readLock().unlock(); + } + } + + @Override + public String toString() { + return "Client[id=" + id + ", type=" + clientType + "] consumerId=" + (consumer != null ? consumer.getConsumerId() : "null"); + } + } + + /** + * Sweeps out not-used durable subscriptions. + */ + private final class HouseKeeper extends Thread { + + private HouseKeeper() { + super("HouseKeeper"); + setDaemon(true); + } + + public final CopyOnWriteArrayList abandonedSubscriptions = new CopyOnWriteArrayList(); + + @Override + public void run() { + while (true) { + try { + Thread.sleep(3 * 60 * 1000); + + processLock.readLock().lock(); + try { + sweep(); + } finally { + processLock.readLock().unlock(); + } + } catch (InterruptedException ex) { + break; + } catch (Throwable e) { + Exception log = new Exception("HouseKeeper failed.", e); + log.printStackTrace(); + } + } + } + + private void sweep() throws Exception { + LOG.info("Housekeeper sweeping."); + + int closed = 0; + ArrayList sweeped = new ArrayList(); + try { + for (String clientId : abandonedSubscriptions) { + LOG.info("Sweeping out subscription of " + + clientId + "."); + broker.getAdminView().destroyDurableSubscriber(clientId, + Client.SUBSCRIPTION_NAME); + sweeped.add(clientId); + closed++; + } + } catch (Exception ignored) { + LOG.info("Ex on destroy sub " + ignored); + } finally { + abandonedSubscriptions.removeAll(sweeped); + } + + LOG.info("Housekeeper sweeped out " + closed + + " subscriptions."); + } + } + + public static int random(int max) { + return (int) (Math.random() * (max + 1)); + } + + public static int random(int min, int max) { + return random(max - min) + min; + } + + public static void sleepRandom(int maxMillis) throws InterruptedException { + Thread.sleep(random(maxMillis)); + } + + public static void sleepRandom(int minMillis, int maxMillis) + throws InterruptedException { + Thread.sleep(random(minMillis, maxMillis)); + } + + public static final class Random { + + final int min; + final int max; + + Random(int min, int max) { + this.min = min; + this.max = max; + } + + public int next() { + return random(min, max); + } + + public void sleepRandom() throws InterruptedException { + DurableSubProcessConcurrentCommitActivateNoDuplicateTest.sleepRandom(min, max); + } + } + + public static void exit(String message) { + exit(message, null); + } + + public static void exit(String message, Throwable e) { + Throwable cause = new RuntimeException(message, e); + LOG.error(message, cause); + exceptions.add(cause); + ThreadTracker.result(); + //fail(cause.toString()); + System.exit(-9); + } + + @Before + public void setUp() throws Exception { + topic = new ActiveMQTopic("TopicT"); + startBroker(); + + clientManager = new ClientManager(); + server = new Server(); + houseKeeper = new HouseKeeper(); + + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + private enum Persistence { + MEMORY, LEVELDB, KAHADB + } + + private void startBroker() throws Exception { + startBroker(true); + } + + private void startBroker(boolean deleteAllMessages) throws Exception { + if (broker != null) + return; + + broker = BrokerFactory.createBroker("broker:(vm://" + getName() + ")"); + broker.setBrokerName(getName()); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + + switch (PERSISTENT_ADAPTER) { + case MEMORY: + broker.setPersistent(false); + break; + + case LEVELDB: + File amqData = new File("activemq-data/" + getName() + "-leveldb"); + if (deleteAllMessages) + delete(amqData); + + broker.setPersistent(true); + LevelDBStore amq = new LevelDBStore(); + amq.setDirectory(amqData); + broker.setPersistenceAdapter(amq); + break; + + case KAHADB: + File kahadbData = new File("activemq-data/" + getName() + "-kahadb"); + if (deleteAllMessages) + delete(kahadbData); + + broker.setPersistent(true); + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setDirectory(kahadbData); + kahadb.setJournalMaxFileLength(5 * 1024 * 1024); + broker.setPersistenceAdapter(kahadb); + break; + } + + broker.addConnector("tcp://localhost:61656"); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getTempUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getStoreUsage().setLimit(1024 * 1024 * 1024); + + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setMaxAuditDepth(20000); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + broker.start(); + } + + protected static String getName() { + return "DurableSubProcessWithRestartTest"; + } + + private static boolean delete(File path) { + if (path == null) + return true; + + if (path.isDirectory()) { + for (File file : path.listFiles()) { + delete(file); + } + } + return path.delete(); + } + + private void destroyBroker() throws Exception { + if (broker == null) + return; + + broker.stop(); + broker = null; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessMultiRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessMultiRestartTest.java new file mode 100644 index 0000000000..8d3117b73f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessMultiRestartTest.java @@ -0,0 +1,409 @@ +/** + * 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 ONDITIONS 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.usecases; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.transport.InactivityIOException; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubProcessMultiRestartTest { + private static final Logger LOG = LoggerFactory.getLogger(DurableSubProcessMultiRestartTest.class); + + public static final long RUNTIME = 1 * 60 * 1000; + + private BrokerService broker; + private ActiveMQTopic topic; + + private final ReentrantReadWriteLock processLock = new ReentrantReadWriteLock(true); + + private int restartCount = 0; + private final int SUBSCRIPTION_ID = 1; + + static final Vector exceptions = new Vector(); + + /** + * The test creates a durable subscriber and producer with a broker that is + * continually restarted. + * + * Producer creates a message every .5 seconds -creates a new connection for + * each message + * + * durable subscriber - comes online for 10 seconds, - then goes offline for + * a "moment" - repeats the cycle + * + * approx every 10 seconds the broker restarts. Subscriber and Producer + * connections will be closed BEFORE the restart. + * + * The Durable subscriber is "unsubscribed" before the the end of the test. + * + * checks for number of kahaDB files left on filesystem. + * + * @throws Exception + */ + @Test + public void testProcess() throws Exception { + + DurableSubscriber durableSubscriber = new DurableSubscriber(SUBSCRIPTION_ID); + MsgProducer msgProducer = new MsgProducer(); + + try { + // register the subscription & start messages + durableSubscriber.start(); + msgProducer.start(); + + long endTime = System.currentTimeMillis() + RUNTIME; + + while (endTime > System.currentTimeMillis()) { + Thread.sleep(10000); + restartBroker(); + } + } catch (Throwable e) { + exit("ProcessTest.testProcess failed.", e); + } + + // wait for threads to finish + try { + msgProducer.join(); + durableSubscriber.join(); + } catch (InterruptedException e) { + e.printStackTrace(System.out); + } + + // restart broker one last time + restartBroker(); + + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + + final KahaDBPersistenceAdapter pa = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + assertTrue("only less than two journal files should be left: " + pa.getStore().getJournal().getFileMap().size(), + Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return pa.getStore().getJournal().getFileMap().size() <= 2; + } + }, TimeUnit.MINUTES.toMillis(3)) + ); + + LOG.info("DONE."); + } + + private void restartBroker() throws Exception { + LOG.info("Broker restart: waiting for components."); + + processLock.writeLock().lock(); + try { + destroyBroker(); + startBroker(false); + + restartCount++; + LOG.info("Broker restarted. count: " + restartCount); + } finally { + processLock.writeLock().unlock(); + } + } + + /** + * Producers messages + * + */ + final class MsgProducer extends Thread { + + String url = "vm://" + DurableSubProcessMultiRestartTest.getName(); + + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + private long msgCount; + int messageRover = 0; + + public MsgProducer() { + super("MsgProducer"); + setDaemon(true); + } + + @Override + public void run() { + + long endTime = RUNTIME + System.currentTimeMillis(); + + try { + while (endTime > System.currentTimeMillis()) { + + Thread.sleep(500); + + processLock.readLock().lock(); + try { + send(); + } finally { + processLock.readLock().unlock(); + } + LOG.info("MsgProducer msgCount=" + msgCount); + } + } catch (Throwable e) { + exit("Server.run failed", e); + } + } + + public void send() throws JMSException { + + LOG.info("Sending ... "); + + Connection con = cf.createConnection(); + + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer prod = sess.createProducer(null); + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setBooleanProperty("COMMIT", true); + prod.send(topic, message); + + msgCount++; + LOG.info("Message Sent."); + + sess.close(); + con.close(); + } + } + + /** + * Consumes massages from a durable subscription. Goes online/offline + * periodically. + */ + private final class DurableSubscriber extends Thread { + + String url = "tcp://localhost:61656"; + + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + public static final String SUBSCRIPTION_NAME = "subscription"; + + private final int id; + private final String conClientId; + private long msgCount; + + public DurableSubscriber(int id) throws JMSException { + super("DurableSubscriber" + id); + setDaemon(true); + + this.id = id; + conClientId = "cli" + id; + + subscribe(); + } + + @Override + public void run() { + + long end = System.currentTimeMillis() + RUNTIME; + + try { + + // while (true) { + while (end > System.currentTimeMillis()) { + + processLock.readLock().lock(); + try { + process(5000); + } finally { + processLock.readLock().unlock(); + } + } + + unsubscribe(); + + } catch (JMSException maybe) { + if (maybe.getCause() instanceof IOException) { + // ok on broker shutdown; + } else { + exit(toString() + " failed with JMSException", maybe); + } + } catch (Throwable e) { + exit(toString() + " failed.", e); + } + + LOG.info(toString() + " DONE. MsgCout=" + msgCount); + } + + private void process(long duration) throws JMSException { + LOG.info(toString() + " ONLINE."); + + Connection con = openConnection(); + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = sess.createDurableSubscriber(topic, SUBSCRIPTION_NAME); + + long end = System.currentTimeMillis() + duration; + + try { + while (end > System.currentTimeMillis()) { + Message message = consumer.receive(100); + if (message != null) { + LOG.info(toString() + "received message..."); + msgCount++; + } + } + } finally { + sess.close(); + con.close(); + LOG.info(toString() + " OFFLINE."); + } + } + + private Connection openConnection() throws JMSException { + Connection con = cf.createConnection(); + con.setClientID(conClientId); + con.start(); + return con; + } + + private void subscribe() throws JMSException { + Connection con = openConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + session.createDurableSubscriber(topic, SUBSCRIPTION_NAME); + LOG.info(toString() + " SUBSCRIBED"); + + session.close(); + con.close(); + } + + private void unsubscribe() throws JMSException { + Connection con = openConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe(SUBSCRIPTION_NAME); + LOG.info(toString() + " UNSUBSCRIBED"); + + session.close(); + con.close(); + } + + @Override + public String toString() { + return "DurableSubscriber[id=" + id + "]"; + } + } + + // -------- helper methods ----------- + + public static void exit(String message) { + exit(message, null); + } + + public static void exit(String message, Throwable e) { + Throwable cause = new RuntimeException(message, e); + LOG.error(message, cause); + exceptions.add(cause); + fail(cause.toString()); + } + + @Before + public void setUp() throws Exception { + topic = new ActiveMQTopic("TopicT"); + startBroker(); + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + private void startBroker() throws Exception { + startBroker(true); + } + + private void startBroker(boolean deleteAllMessages) throws Exception { + if (broker != null) + return; + + broker = BrokerFactory.createBroker("broker:(vm://" + getName() + ")"); + broker.setBrokerName(getName()); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + + broker.setKeepDurableSubsActive(true); + + File kahadbData = new File("activemq-data/" + getName() + "-kahadb"); + if (deleteAllMessages) + delete(kahadbData); + + broker.setPersistent(true); + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setDirectory(kahadbData); + kahadb.setJournalMaxFileLength(20 * 1024); + broker.setPersistenceAdapter(kahadb); + + broker.addConnector("tcp://localhost:61656"); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getTempUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getStoreUsage().setLimit(256 * 1024 * 1024); + + broker.start(); + } + + protected static String getName() { + return "DurableSubProcessMultiRestartTest"; + } + + private static boolean delete(File path) { + if (path == null) + return true; + + if (path.isDirectory()) { + for (File file : path.listFiles()) { + delete(file); + } + } + return path.delete(); + } + + private void destroyBroker() throws Exception { + if (broker == null) + return; + + broker.stop(); + broker = null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessTest.java new file mode 100644 index 0000000000..71ab687cdd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessTest.java @@ -0,0 +1,678 @@ +/** + * 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.usecases; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.junit.Test; + +import javax.jms.*; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.Vector; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; + +// see https://issues.apache.org/activemq/browse/AMQ-2985 +// this demonstrated receiving old messages eventually along with validating order receipt +public class DurableSubProcessTest extends org.apache.activemq.TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(DurableSubProcessTest.class); + public static final long RUNTIME = 4 * 60 * 1000; + + public static final int SERVER_SLEEP = 2 * 1000; // max + public static final int CARGO_SIZE = 10; // max + + public static final int MAX_CLIENTS = 7; + public static final Random CLIENT_LIFETIME = new Random(30 * 1000, 2 * 60 * 1000); + public static final Random CLIENT_ONLINE = new Random(2 * 1000, 15 * 1000); + public static final Random CLIENT_OFFLINE = new Random(1 * 1000, 20 * 1000); + + public static final boolean PERSISTENT_BROKER = true; + public static final boolean ALLOW_SUBSCRIPTION_ABANDONMENT = true; + + + private BrokerService broker; + private ActiveMQTopic topic; + + private ClientManager clientManager; + private Server server; + private HouseKeeper houseKeeper; + + static final Vector exceptions = new Vector(); + + @Test + public void testProcess() { + try { + server.start(); + clientManager.start(); + + if (ALLOW_SUBSCRIPTION_ABANDONMENT) + houseKeeper.start(); + + Thread.sleep(RUNTIME); + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + } + catch (Throwable e) { + exit("DurableSubProcessTest.testProcess failed.", e); + } + LOG.info("DONE."); + } + + /** + * Creates batch of messages in a transaction periodically. + * The last message in the transaction is always a special + * message what contains info about the whole transaction. + *

Notifies the clients about the created messages also. + */ + final class Server extends Thread { + + final String url = "vm://" + DurableSubProcessTest.this.getName() + "?" + + "jms.redeliveryPolicy.maximumRedeliveries=2&jms.redeliveryPolicy.initialRedeliveryDelay=500&" + + "jms.producerWindowSize=20971520&jms.prefetchPolicy.all=100&" + + "jms.copyMessageOnSend=false&jms.disableTimeStampsByDefault=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=false&" + + "jms.watchTopicAdvisories=false&" + + "waitForStart=200&create=false"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + final Object sendMutex = new Object(); + final String[] cargos = new String[500]; + + int transRover = 0; + int messageRover = 0; + + public Server() { + super("Server"); + setDaemon(true); + } + + @Override + public void run() { + try { + while (true) { + DurableSubProcessTest.sleepRandom(SERVER_SLEEP); + send(); + } + } + catch (Throwable e) { + exit("Server.run failed", e); + } + } + + public void send() throws JMSException { + // do not create new clients now + // ToDo: Test this case later. + synchronized (sendMutex) { + int trans = ++transRover; + boolean relevantTrans = random(2) > 1; + ClientType clientType = relevantTrans ? ClientType.randomClientType() : null; // sends this types + int count = random(200); + + LOG.info("Sending Trans[id=" + trans + ", count=" + count + ", clientType=" + clientType + "]"); + + Connection con = cf.createConnection(); + Session sess = con.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageProducer prod = sess.createProducer(null); + + for (int i = 0; i < count; i++) { + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + String type = clientType != null ? clientType.randomMessageType() : ClientType.randomNonRelevantMessageType(); + message.setStringProperty("TYPE", type); + + if (CARGO_SIZE > 0) + message.setStringProperty("CARGO", getCargo(CARGO_SIZE)); + + prod.send(topic, message); + clientManager.onServerMessage(message); + } + + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("COMMIT", true); + message.setBooleanProperty("RELEVANT", relevantTrans); + prod.send(topic, message); + clientManager.onServerMessage(message); + + sess.commit(); + sess.close(); + con.close(); + } + } + + private String getCargo(int length) { + if (length == 0) + return null; + + if (length < cargos.length) { + String result = cargos[length]; + if (result == null) { + result = getCargoImpl(length); + cargos[length] = result; + } + return result; + } + return getCargoImpl(length); + } + + private String getCargoImpl(int length) { + StringBuilder sb = new StringBuilder(length); + for (int i = length; --i >=0; ) { + sb.append('a'); + } + return sb.toString(); + } + } + + /** + * Clients listen on different messages in the topic. + * The 'TYPE' property helps the client to select the + * proper messages. + */ + private enum ClientType { + A ("a", "b", "c"), + B ("c", "d", "e"), + C ("d", "e", "f"), + D ("g", "h"); + + public final String[] messageTypes; + public final HashSet messageTypeSet; + public final String selector; + + ClientType(String... messageTypes) { + this.messageTypes = messageTypes; + messageTypeSet = new HashSet(Arrays.asList(messageTypes)); + + StringBuilder sb = new StringBuilder("TYPE in ("); + for (int i = 0; i < messageTypes.length; i++) { + if (i > 0) + sb.append(", "); + sb.append('\'').append(messageTypes[i]).append('\''); + } + sb.append(')'); + selector = sb.toString(); + } + + public static ClientType randomClientType() { + return values()[DurableSubProcessTest.random(values().length - 1)]; + } + + public final String randomMessageType() { + return messageTypes[DurableSubProcessTest.random(messageTypes.length - 1)]; + } + + public static String randomNonRelevantMessageType() { + return Integer.toString(DurableSubProcessTest.random(20)); + } + + public final boolean isRelevant(String messageType) { + return messageTypeSet.contains(messageType); + } + + @Override + public final String toString() { + return this.name() /*+ '[' + selector + ']'*/; + } + } + + /** + * Creates new cliens. + */ + private final class ClientManager extends Thread { + + private int clientRover = 0; + + private final CopyOnWriteArrayList clients = new CopyOnWriteArrayList(); + + public ClientManager() { + super("ClientManager"); + setDaemon(true); + } + + @Override + public void run() { + try { + while (true) { + if (clients.size() < MAX_CLIENTS) + createNewClient(); + + int size = clients.size(); + sleepRandom(size * 3 * 1000, size * 6 * 1000); + } + } + catch (Throwable e) { + exit("ClientManager.run failed.", e); + } + } + + private void createNewClient() throws JMSException { + ClientType type = ClientType.randomClientType(); + + Client client; + synchronized (server.sendMutex) { + client = new Client(++clientRover, type, CLIENT_LIFETIME, CLIENT_ONLINE, CLIENT_OFFLINE); + clients.add(client); + } + client.start(); + + LOG.info(client.toString() + " created. " + this); + } + + public void removeClient(Client client) { + clients.remove(client); + } + + public void onServerMessage(Message message) throws JMSException { + for (Client client: clients) { + client.onServerMessage(message); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ClientManager[count="); + sb.append(clients.size()); + sb.append(", clients="); + boolean sep = false; + for (Client client: clients) { + if (sep) sb.append(", "); + else sep = true; + sb.append(client.toString()); + } + sb.append(']'); + return sb.toString(); + } + } + + /** + * Consumes massages from a durable subscription. + * Goes online/offline periodically. Checks the incoming messages + * against the sent messages of the server. + */ + private final class Client extends Thread { + + String url = "failover:(tcp://localhost:61656?wireFormat.maxInactivityDuration=0)?" + + "jms.watchTopicAdvisories=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=true&" + + "jms.producerWindowSize=20971520&" + + "jms.copyMessageOnSend=false&" + + "initialReconnectDelay=100&maxReconnectDelay=30000&" + + "useExponentialBackOff=true"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + public static final String SUBSCRIPTION_NAME = "subscription"; + + private final int id; + private final String conClientId; + + private final Random lifetime; + private final Random online; + private final Random offline; + + private final ClientType clientType; + private final String selector; + + private final ConcurrentLinkedQueue waitingList = new ConcurrentLinkedQueue(); + + public Client(int id, ClientType clientType, Random lifetime, Random online, Random offline) throws JMSException { + super("Client" + id); + setDaemon(true); + + this.id = id; + conClientId = "cli" + id; + this.clientType = clientType; + selector = "(COMMIT = true and RELEVANT = true) or " + clientType.selector; + + this.lifetime = lifetime; + this.online = online; + this.offline = offline; + + subscribe(); + } + + @Override + public void run() { + long end = System.currentTimeMillis() + lifetime.next(); + try { + boolean sleep = false; + while (true) { + long max = end - System.currentTimeMillis(); + if (max <= 0) + break; + + if (sleep) offline.sleepRandom(); + else sleep = true; + + process(online.next()); + } + + if (!ALLOW_SUBSCRIPTION_ABANDONMENT || random(1) > 0) + unsubscribe(); + else { + LOG.info("Client abandon the subscription. " + this); + + // housekeeper should sweep these abandoned subscriptions + houseKeeper.abandonedSubscriptions.add(conClientId); + } + } + catch (Throwable e) { + exit(toString() + " failed.", e); + } + + clientManager.removeClient(this); + LOG.info(toString() + " DONE."); + } + + private void process(long millis) throws JMSException { + long end = System.currentTimeMillis() + millis; + long hardEnd = end + 2000; // wait to finish the transaction. + boolean inTransaction = false; + int transCount = 0; + + LOG.info(toString() + " ONLINE."); + Connection con = openConnection(); + Session sess = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = sess.createDurableSubscriber(topic, SUBSCRIPTION_NAME, selector, false); + try { + do { + long max = end - System.currentTimeMillis(); + if (max <= 0) { + if (!inTransaction) + break; + + max = hardEnd - System.currentTimeMillis(); + if (max <= 0) + exit("" + this + " failed: Transaction is not finished."); + } + + Message message = consumer.receive(max); + if (message == null) + continue; + + onClientMessage(message); + + if (message.propertyExists("COMMIT")) { + message.acknowledge(); + + LOG.info("Received Trans[id=" + message.getIntProperty("TRANS") + ", count=" + transCount + "] in " + this + "."); + + inTransaction = false; + transCount = 0; + } + else { + inTransaction = true; + transCount++; + } + } while (true); + } + finally { + sess.close(); + con.close(); + + LOG.info(toString() + " OFFLINE."); + + // Check if the messages are in the waiting + // list for long time. + Message topMessage = waitingList.peek(); + if (topMessage != null) + checkDeliveryTime(topMessage); + } + } + + public void onServerMessage(Message message) throws JMSException { + if (Boolean.TRUE.equals(message.getObjectProperty("COMMIT"))) { + if (Boolean.TRUE.equals(message.getObjectProperty("RELEVANT"))) + waitingList.add(message); + } + else { + String messageType = message.getStringProperty("TYPE"); + if (clientType.isRelevant(messageType)) + waitingList.add(message); + } + } + + public void onClientMessage(Message message) { + Message serverMessage = waitingList.poll(); + try { + if (serverMessage == null) + exit("" + this + " failed: There is no next server message, but received: " + message); + + Integer receivedId = (Integer) message.getObjectProperty("ID"); + Integer serverId = (Integer) serverMessage.getObjectProperty("ID"); + if (receivedId == null || serverId == null) + exit("" + this + " failed: message ID not found.\r\n" + + " received: " + message + "\r\n" + + " server: " + serverMessage); + + if (!serverId.equals(receivedId)) + exit("" + this + " failed: Received wrong message.\r\n" + + " received: " + message + "\r\n" + + " server: " + serverMessage); + + checkDeliveryTime(message); + } + catch (Throwable e) { + exit("" + this + ".onClientMessage failed.\r\n" + + " received: " + message + "\r\n" + + " server: " + serverMessage, e); + } + } + + /** + * Checks if the message was not delivered fast enough. + */ + public void checkDeliveryTime(Message message) throws JMSException { + long creation = message.getJMSTimestamp(); + long min = System.currentTimeMillis() - (offline.max + online.min); + + if (min > creation) { + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS"); + exit("" + this + ".checkDeliveryTime failed. Message time: " + df.format(new Date(creation)) + ", min: " + df.format(new Date(min)) + "\r\n" + message); + } + } + + private Connection openConnection() throws JMSException { + Connection con = cf.createConnection(); + con.setClientID(conClientId); + con.start(); + return con; + } + + private void subscribe() throws JMSException { + Connection con = openConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, SUBSCRIPTION_NAME, selector, true); + session.close(); + con.close(); + } + + private void unsubscribe() throws JMSException { + Connection con = openConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe(SUBSCRIPTION_NAME); + session.close(); + con.close(); + } + + @Override + public String toString() { + return "Client[id=" + id + ", type=" + clientType + "]"; + } + } + + /** + * Sweeps out not-used durable subscriptions. + */ + private final class HouseKeeper extends Thread { + + private HouseKeeper() { + super("HouseKeeper"); + setDaemon(true); + } + + public final CopyOnWriteArrayList abandonedSubscriptions = new CopyOnWriteArrayList(); + + @Override + public void run() { + while (true) { + try { + Thread.sleep(60 * 1000); + sweep(); + } + catch (InterruptedException ex) { + break; + } + catch (Throwable e) { + Exception log = new Exception("HouseKeeper failed.", e); + log.printStackTrace(); + } + } + } + + private void sweep() throws Exception { + LOG.info("Housekeeper sweeping."); + + int closed = 0; + ArrayList sweeped = new ArrayList(); + try { + for (String clientId: abandonedSubscriptions) { + sweeped.add(clientId); + LOG.info("Sweeping out subscription of " + clientId + "."); + broker.getAdminView().destroyDurableSubscriber(clientId, Client.SUBSCRIPTION_NAME); + closed++; + } + } + finally { + abandonedSubscriptions.removeAll(sweeped); + } + + LOG.info("Housekeeper sweeped out " + closed + " subscriptions."); + } + } + + public static int random(int max) { + return (int) (Math.random() * (max + 1)); + } + + public static int random(int min, int max) { + return random(max - min) + min; + } + + public static void sleepRandom(int maxMillis) throws InterruptedException { + Thread.sleep(random(maxMillis)); + } + + public static void sleepRandom(int minMillis, int maxMillis) throws InterruptedException { + Thread.sleep(random(minMillis, maxMillis)); + } + + public static final class Random { + + final int min; + final int max; + + Random(int min, int max) { + this.min = min; + this.max = max; + } + + public int next() { + return random(min, max); + } + + public void sleepRandom() throws InterruptedException { + DurableSubProcessTest.sleepRandom(min, max); + } + } + + public static void exit(String message) { + exit(message, null); + } + + public static void exit(String message, Throwable e) { + Throwable log = new RuntimeException(message, e); + log.printStackTrace(); + LOG.error(message, e); + exceptions.add(e); + fail(message); + } + + protected void setUp() throws Exception { + topic = (ActiveMQTopic) createDestination(); + startBroker(); + + clientManager = new ClientManager(); + server = new Server(); + houseKeeper = new HouseKeeper(); + + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + + destroyBroker(); + } + + private void startBroker() throws Exception { + startBroker(true); + } + + private void startBroker(boolean deleteAllMessages) throws Exception { + if (broker != null) + return; + + broker = BrokerFactory.createBroker("broker:(vm://localhost)"); + broker.setBrokerName(getName()); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + + if (PERSISTENT_BROKER) { + broker.setPersistent(true); + KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); + persistenceAdapter.setDirectory(new File("activemq-data/" + getName())); + broker.setPersistenceAdapter(persistenceAdapter); + } + else + broker.setPersistent(false); + + broker.addConnector("tcp://localhost:61656"); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getTempUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getStoreUsage().setLimit(256 * 1024 * 1024); + + broker.start(); + } + + private void destroyBroker() throws Exception { + if (broker == null) + return; + + broker.stop(); + broker = null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessWithRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessWithRestartTest.java new file mode 100644 index 0000000000..c190952c15 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubProcessWithRestartTest.java @@ -0,0 +1,832 @@ +/** + * 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 ONDITIONS 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.usecases; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.Vector; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubProcessWithRestartTest { + private static final Logger LOG = LoggerFactory.getLogger(DurableSubProcessWithRestartTest.class); + public static final long RUNTIME = 5 * 60 * 1000; + + public static final int SERVER_SLEEP = 2 * 1000; // max + public static final int CARGO_SIZE = 400; // max + + public static final int MAX_CLIENTS = 5; + public static final Random CLIENT_LIFETIME = new Random(5 * 1000, + 2 * 5 * 1000); + public static final Random CLIENT_ONLINE = new Random(2 * 1000, 2 * 1000); + public static final Random CLIENT_OFFLINE = new Random(10 * 1000, 10 * 1000); + + public static final Persistence PERSISTENT_ADAPTER = Persistence.KAHADB; + public static final long BROKER_RESTART = 1 * 10 * 1000; + + public static final boolean ALLOW_SUBSCRIPTION_ABANDONMENT = true; + public static final boolean CHECK_REDELIVERY = true; + + private BrokerService broker; + private ActiveMQTopic topic; + + private ClientManager clientManager; + private Server server; + private HouseKeeper houseKeeper; + + private final ReentrantReadWriteLock processLock = new ReentrantReadWriteLock( + true); + private int restartCount = 0; + static final Vector exceptions = new Vector(); + + // this is a nice test but it takes 5mins, may be handy in the future + // resulting bug https://issues.apache.org/jira/browse/AMQ-3190 + @Ignore("covered by org.apache.activemq.usecases.DurableSubscriptionOfflineTest.testNoMissOnMatchingSubAfterRestart()") @Test + public void testProcess() { + try { + server.start(); + clientManager.start(); + + if (ALLOW_SUBSCRIPTION_ABANDONMENT) + houseKeeper.start(); + + long end = System.currentTimeMillis() + RUNTIME; + + while (true) { + long now = System.currentTimeMillis(); + if (now > end) + break; + + now = end - now; + now = now < BROKER_RESTART ? now : BROKER_RESTART; + Thread.sleep(now); + + restartBroker(); + } + } catch (Throwable e) { + exit("ProcessTest.testProcess failed.", e); + } + + processLock.writeLock().lock(); + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + LOG.info("DONE."); + } + + private void restartBroker() throws Exception { + LOG.info("Broker restart: waiting for components."); + + processLock.writeLock().lock(); + try { + destroyBroker(); + startBroker(false); + + restartCount++; + LOG.info("Broker restarted. count: " + restartCount); + } finally { + processLock.writeLock().unlock(); + } + } + + /** + * Creates batch of messages in a transaction periodically. The last message + * in the transaction is always a special message what contains info about + * the whole transaction. + *

+ * Notifies the clients about the created messages also. + */ + final class Server extends Thread { + + final String url = "vm://" + + DurableSubProcessWithRestartTest.getName() + + "?" + + "jms.redeliveryPolicy.maximumRedeliveries=2&jms.redeliveryPolicy.initialRedeliveryDelay=500&" + + "jms.producerWindowSize=20971520&jms.prefetchPolicy.all=100&" + + "jms.copyMessageOnSend=false&jms.disableTimeStampsByDefault=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=false&" + + "jms.watchTopicAdvisories=false&" + + "waitForStart=200&create=false"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + final Object sendMutex = new Object(); + final String[] cargos = new String[500]; + + int transRover = 0; + int messageRover = 0; + + public Server() { + super("Server"); + setDaemon(true); + } + + @Override + public void run() { + try { + while (true) { + DurableSubProcessWithRestartTest.sleepRandom(SERVER_SLEEP); + + processLock.readLock().lock(); + try { + send(); + } finally { + processLock.readLock().unlock(); + } + } + } catch (Throwable e) { + exit("Server.run failed", e); + } + } + + public void send() throws JMSException { + // do not create new clients now + // ToDo: Test this case later. + synchronized (sendMutex) { + int trans = ++transRover; + boolean relevantTrans = random(2) > 1; + ClientType clientType = relevantTrans ? ClientType + .randomClientType() : null; // sends this types + int count = random(200); + + LOG.info("Sending Trans[id=" + trans + ", count=" + + count + ", clientType=" + clientType + "]"); + + Connection con = cf.createConnection(); + Session sess = con + .createSession(true, Session.SESSION_TRANSACTED); + MessageProducer prod = sess.createProducer(null); + + for (int i = 0; i < count; i++) { + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + String type = clientType != null ? clientType + .randomMessageType() : ClientType + .randomNonRelevantMessageType(); + message.setStringProperty("TYPE", type); + + if (CARGO_SIZE > 0) + message.setStringProperty("CARGO", + getCargo(random(CARGO_SIZE))); + + prod.send(topic, message); + clientManager.onServerMessage(message); + } + + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("COMMIT", true); + message.setBooleanProperty("RELEVANT", relevantTrans); + prod.send(topic, message); + clientManager.onServerMessage(message); + + sess.commit(); + LOG.info("Committed Trans[id=" + trans + ", count=" + + count + ", clientType=" + clientType + "], ID=" + messageRover); + + sess.close(); + con.close(); + } + } + + private String getCargo(int length) { + if (length == 0) + return null; + + if (length < cargos.length) { + String result = cargos[length]; + if (result == null) { + result = getCargoImpl(length); + cargos[length] = result; + } + return result; + } + return getCargoImpl(length); + } + + private String getCargoImpl(int length) { + StringBuilder sb = new StringBuilder(length); + for (int i = length; --i >= 0;) { + sb.append('a'); + } + return sb.toString(); + } + } + + /** + * Clients listen on different messages in the topic. The 'TYPE' property + * helps the client to select the proper messages. + */ + private enum ClientType { + A("a", "b", "c"), B("c", "d", "e"), C("d", "e", "f"), D("g", "h"); + + public final String[] messageTypes; + public final HashSet messageTypeSet; + public final String selector; + + ClientType(String... messageTypes) { + this.messageTypes = messageTypes; + messageTypeSet = new HashSet(Arrays.asList(messageTypes)); + + StringBuilder sb = new StringBuilder("TYPE in ("); + for (int i = 0; i < messageTypes.length; i++) { + if (i > 0) + sb.append(", "); + sb.append('\'').append(messageTypes[i]).append('\''); + } + sb.append(')'); + selector = sb.toString(); + } + + public static ClientType randomClientType() { + return values()[DurableSubProcessWithRestartTest + .random(values().length - 1)]; + } + + public final String randomMessageType() { + return messageTypes[DurableSubProcessWithRestartTest + .random(messageTypes.length - 1)]; + } + + public static String randomNonRelevantMessageType() { + return Integer + .toString(DurableSubProcessWithRestartTest.random(20)); + } + + public final boolean isRelevant(String messageType) { + return messageTypeSet.contains(messageType); + } + + @Override + public final String toString() { + return this.name() /* + '[' + selector + ']' */; + } + } + + /** + * Creates new cliens. + */ + private final class ClientManager extends Thread { + + private int clientRover = 0; + + private final CopyOnWriteArrayList clients = new CopyOnWriteArrayList(); + + public ClientManager() { + super("ClientManager"); + setDaemon(true); + } + + @Override + public void run() { + try { + while (true) { + if (clients.size() < MAX_CLIENTS) { + processLock.readLock().lock(); + try { + createNewClient(); + } finally { + processLock.readLock().unlock(); + } + } + + int size = clients.size(); + sleepRandom(size * 3 * 1000, size * 6 * 1000); + } + } catch (Throwable e) { + exit("ClientManager.run failed.", e); + } + } + + private void createNewClient() throws JMSException { + ClientType type = ClientType.randomClientType(); + + Client client; + synchronized (server.sendMutex) { + client = new Client(++clientRover, type, CLIENT_LIFETIME, + CLIENT_ONLINE, CLIENT_OFFLINE); + clients.add(client); + } + client.start(); + + LOG.info(client.toString() + " created. " + this); + } + + public void removeClient(Client client) { + clients.remove(client); + } + + public void onServerMessage(Message message) throws JMSException { + for (Client client : clients) { + client.onServerMessage(message); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("ClientManager[count="); + sb.append(clients.size()); + sb.append(", clients="); + boolean sep = false; + for (Client client : clients) { + if (sep) + sb.append(", "); + else + sep = true; + sb.append(client.toString()); + } + sb.append(']'); + return sb.toString(); + } + } + + /** + * Consumes massages from a durable subscription. Goes online/offline + * periodically. Checks the incoming messages against the sent messages of + * the server. + */ + private final class Client extends Thread { + + String url = "failover:(tcp://localhost:61656?wireFormat.maxInactivityDuration=0)?" + + "jms.watchTopicAdvisories=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=true&" + + "jms.producerWindowSize=20971520&" + + "jms.copyMessageOnSend=false&" + + "initialReconnectDelay=100&maxReconnectDelay=30000&" + + "useExponentialBackOff=true"; + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + public static final String SUBSCRIPTION_NAME = "subscription"; + + private final int id; + private final String conClientId; + + private final Random lifetime; + private final Random online; + private final Random offline; + + private final ClientType clientType; + private final String selector; + + private final ConcurrentLinkedQueue waitingList = new ConcurrentLinkedQueue(); + private final HashSet processed = CHECK_REDELIVERY ? new HashSet( + 10000) : null; + + public Client(int id, ClientType clientType, Random lifetime, + Random online, Random offline) throws JMSException { + super("Client" + id); + setDaemon(true); + + this.id = id; + conClientId = "cli" + id; + this.clientType = clientType; + selector = "(COMMIT = true and RELEVANT = true) or " + + clientType.selector; + + this.lifetime = lifetime; + this.online = online; + this.offline = offline; + + subscribe(); + } + + @Override + public void run() { + long end = System.currentTimeMillis() + lifetime.next(); + try { + boolean sleep = false; + while (true) { + long max = end - System.currentTimeMillis(); + if (max <= 0) + break; + + if (sleep) + offline.sleepRandom(); + else + sleep = true; + + processLock.readLock().lock(); + try { + process(online.next()); + } finally { + processLock.readLock().unlock(); + } + } + + if (!ALLOW_SUBSCRIPTION_ABANDONMENT || random(1) > 0) + unsubscribe(); + else { + LOG.info("Client abandon the subscription. " + + this); + + // housekeeper should sweep these abandoned subscriptions + houseKeeper.abandonedSubscriptions.add(conClientId); + } + } catch (Throwable e) { + exit(toString() + " failed.", e); + } + + clientManager.removeClient(this); + LOG.info(toString() + " DONE."); + } + + private void process(long millis) throws JMSException { + long end = System.currentTimeMillis() + millis; + long hardEnd = end + 20000; // wait to finish the transaction. + boolean inTransaction = false; + int transCount = 0; + + LOG.info(toString() + " ONLINE."); + Connection con = openConnection(); + Session sess = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = sess.createDurableSubscriber(topic, + SUBSCRIPTION_NAME, selector, false); + try { + do { + long max = end - System.currentTimeMillis(); + if (max <= 0) { + if (!inTransaction) + break; + + max = hardEnd - System.currentTimeMillis(); + if (max <= 0) + exit("" + this + + " failed: Transaction is not finished."); + } + + Message message = consumer.receive(max); + if (message == null) + continue; + + onClientMessage(message); + + if (message.propertyExists("COMMIT")) { + message.acknowledge(); // CLIENT_ACKNOWLEDGE + + LOG.info("Received Trans[id=" + + message.getIntProperty("TRANS") + ", count=" + + transCount + "] in " + this + "."); + + inTransaction = false; + transCount = 0; + } else { + inTransaction = true; + transCount++; + } + } while (true); + } finally { + sess.close(); + con.close(); + + LOG.info(toString() + " OFFLINE."); + + // Check if the messages are in the waiting + // list for long time. + Message topMessage = waitingList.peek(); + if (topMessage != null) + checkDeliveryTime(topMessage); + } + } + + public void onServerMessage(Message message) throws JMSException { + if (Boolean.TRUE.equals(message.getObjectProperty("COMMIT"))) { + if (Boolean.TRUE.equals(message.getObjectProperty("RELEVANT"))) + waitingList.add(message); + } else { + String messageType = message.getStringProperty("TYPE"); + if (clientType.isRelevant(messageType)) + waitingList.add(message); + } + } + + public void onClientMessage(Message message) { + Message serverMessage = waitingList.poll(); + try { + Integer receivedId = (Integer) message.getObjectProperty("ID"); + if (processed != null && processed.contains(receivedId)) + LOG.info("! Message has been processed before. " + + this + " message = " + message); + + if (serverMessage == null) + exit("" + + this + + " failed: There is no next server message, but received: " + + message); + + Integer serverId = (Integer) serverMessage + .getObjectProperty("ID"); + if (receivedId == null || serverId == null) + exit("" + this + " failed: message ID not found.\r\n" + + " received: " + message + "\r\n" + " server: " + + serverMessage); + + if (!serverId.equals(receivedId)) { + String detail = processed != null ? + Arrays.toString(processed.toArray()) + "\n" + : ""; + exit(detail + this + " failed: Received wrong message.\r\n" + + " received: " + message + "\r\n" + " server: " + + serverMessage); + } + + checkDeliveryTime(message); + + if (processed != null) + processed.add(receivedId); + } catch (Throwable e) { + exit("" + this + ".onClientMessage failed.\r\n" + " received: " + + message + "\r\n" + " server: " + serverMessage, e); + } + } + + /** + * Checks if the message was not delivered fast enough. + */ + @SuppressWarnings("unused") + public void checkDeliveryTime(Message message) throws JMSException { + long creation = message.getJMSTimestamp(); + long min = System.currentTimeMillis() - (offline.max + online.min) + * (BROKER_RESTART > 0 ? 4 : 1); + + if (false && min > creation) { + SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS"); + exit("" + this + ".checkDeliveryTime failed. Message time: " + + df.format(new Date(creation)) + ", min: " + + df.format(new Date(min)) + "\r\n" + message); + } + } + + private Connection openConnection() throws JMSException { + Connection con = cf.createConnection(); + con.setClientID(conClientId); + con.start(); + return con; + } + + private void subscribe() throws JMSException { + Connection con = openConnection(); + Session session = con + .createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, SUBSCRIPTION_NAME, selector, + true); + session.close(); + con.close(); + } + + private void unsubscribe() throws JMSException { + Connection con = openConnection(); + Session session = con + .createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe(SUBSCRIPTION_NAME); + session.close(); + con.close(); + } + + @Override + public String toString() { + return "Client[id=" + id + ", type=" + clientType + "]"; + } + } + + /** + * Sweeps out not-used durable subscriptions. + */ + private final class HouseKeeper extends Thread { + + private HouseKeeper() { + super("HouseKeeper"); + setDaemon(true); + } + + public final CopyOnWriteArrayList abandonedSubscriptions = new CopyOnWriteArrayList(); + + @Override + public void run() { + while (true) { + try { + Thread.sleep(3 * 60 * 1000); + + processLock.readLock().lock(); + try { + sweep(); + } finally { + processLock.readLock().unlock(); + } + } catch (InterruptedException ex) { + break; + } catch (Throwable e) { + Exception log = new Exception("HouseKeeper failed.", e); + log.printStackTrace(); + } + } + } + + private void sweep() throws Exception { + LOG.info("Housekeeper sweeping."); + + int closed = 0; + ArrayList sweeped = new ArrayList(); + try { + for (String clientId : abandonedSubscriptions) { + LOG.info("Sweeping out subscription of " + + clientId + "."); + broker.getAdminView().destroyDurableSubscriber(clientId, + Client.SUBSCRIPTION_NAME); + sweeped.add(clientId); + closed++; + } + } catch (Exception ignored) { + LOG.info("Ex on destroy sub " + ignored); + } finally { + abandonedSubscriptions.removeAll(sweeped); + } + + LOG.info("Housekeeper sweeped out " + closed + + " subscriptions."); + } + } + + public static int random(int max) { + return (int) (Math.random() * (max + 1)); + } + + public static int random(int min, int max) { + return random(max - min) + min; + } + + public static void sleepRandom(int maxMillis) throws InterruptedException { + Thread.sleep(random(maxMillis)); + } + + public static void sleepRandom(int minMillis, int maxMillis) + throws InterruptedException { + Thread.sleep(random(minMillis, maxMillis)); + } + + public static final class Random { + + final int min; + final int max; + + Random(int min, int max) { + this.min = min; + this.max = max; + } + + public int next() { + return random(min, max); + } + + public void sleepRandom() throws InterruptedException { + DurableSubProcessWithRestartTest.sleepRandom(min, max); + } + } + + public static void exit(String message) { + exit(message, null); + } + + public static void exit(String message, Throwable e) { + Throwable cause = new RuntimeException(message, e); + LOG.error(message, cause); + exceptions.add(cause); + fail(cause.toString()); + } + + @Before + public void setUp() throws Exception { + topic = new ActiveMQTopic("TopicT"); + startBroker(); + + clientManager = new ClientManager(); + server = new Server(); + houseKeeper = new HouseKeeper(); + + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + private enum Persistence { + MEMORY, LEVELDB, KAHADB + } + + private void startBroker() throws Exception { + startBroker(true); + } + + private void startBroker(boolean deleteAllMessages) throws Exception { + if (broker != null) + return; + + broker = BrokerFactory.createBroker("broker:(vm://" + getName() + ")"); + broker.setBrokerName(getName()); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + + switch (PERSISTENT_ADAPTER) { + case MEMORY: + broker.setPersistent(false); + break; + + case LEVELDB: + File datadir = new File("activemq-data/" + getName() + "-leveldb"); + if (deleteAllMessages) + delete(datadir); + + broker.setPersistent(true); + LevelDBStore amq = new LevelDBStore(); + amq.setDirectory(datadir); + broker.setPersistenceAdapter(amq); + break; + + case KAHADB: + File kahadbData = new File("activemq-data/" + getName() + "-kahadb"); + if (deleteAllMessages) + delete(kahadbData); + + broker.setPersistent(true); + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setDirectory(kahadbData); + kahadb.setJournalMaxFileLength(5 * 1024 * 1024); + broker.setPersistenceAdapter(kahadb); + break; + } + + broker.addConnector("tcp://localhost:61656"); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getTempUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getStoreUsage().setLimit(256 * 1024 * 1024); + + broker.start(); + } + + protected static String getName() { + return "DurableSubProcessWithRestartTest"; + } + + private static boolean delete(File path) { + if (path == null) + return true; + + if (path.isDirectory()) { + for (File file : path.listFiles()) { + delete(file); + } + } + return path.delete(); + } + + private void destroyBroker() throws Exception { + if (broker == null) + return; + + broker.stop(); + broker = null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubSelectorDelayTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubSelectorDelayTest.java new file mode 100644 index 0000000000..f17db91cea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubSelectorDelayTest.java @@ -0,0 +1,309 @@ +/** + * 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 ONDITIONS 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.usecases; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubSelectorDelayTest { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubSelectorDelayTest.class); + + public static final long RUNTIME = 3 * 60 * 1000; + + private BrokerService broker; + private ActiveMQTopic topic; + private String connectionUri; + + @Test + public void testProcess() throws Exception { + + MsgProducer msgProducer = new MsgProducer(); + msgProducer.start(); + + DurableSubscriber subscribers[] = new DurableSubscriber[10]; + + for (int i = 0; i < subscribers.length; i++) { + subscribers[i] = new DurableSubscriber(i); + subscribers[i].process(); + } + + // wait for server to finish + msgProducer.join(); + + for (int j = 0; j < subscribers.length; j++) { + LOG.info("Unsubscribing subscriber " + subscribers[j]); + subscribers[j].unsubscribe(); + } + + // allow the clean up thread time to run + TimeUnit.MINUTES.sleep(2); + + final KahaDBPersistenceAdapter pa = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + assertTrue("less than two journal file should be left, was: " + pa.getStore().getJournal().getFileMap().size(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return pa.getStore().getJournal().getFileMap().size() <= 2; + } + }, TimeUnit.MINUTES.toMillis(2))); + + LOG.info("DONE."); + } + + /** + * Message Producer + */ + final class MsgProducer extends Thread { + + final String url = "vm://" + DurableSubSelectorDelayTest.getName(); + + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + int transRover = 0; + int messageRover = 0; + int count = 40; + + public MsgProducer() { + super("MsgProducer"); + setDaemon(true); + } + + public MsgProducer(int count) { + super("MsgProducer"); + setDaemon(true); + this.count = count; + } + + @Override + public void run() { + long endTime = RUNTIME + System.currentTimeMillis(); + + try { + while (endTime > System.currentTimeMillis()) { + Thread.sleep(400); + send(); + } + } catch (Throwable e) { + e.printStackTrace(System.out); + throw new RuntimeException(e); + } + } + + public void send() throws JMSException { + + int trans = ++transRover; + boolean relevantTrans = true; + + LOG.info("Sending Trans[id=" + trans + ", count=" + count + "]"); + + Connection con = cf.createConnection(); + + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer prod = sess.createProducer(null); + + for (int i = 0; i < count; i++) { + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("RELEVANT", false); + prod.send(topic, message); + } + + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("COMMIT", true); + message.setBooleanProperty("RELEVANT", relevantTrans); + prod.send(topic, message); + + LOG.info("Committed Trans[id=" + trans + ", count=" + count + "], ID=" + messageRover); + + sess.close(); + con.close(); + } + } + + /** + * Consumes massages from a durable subscription. Goes online/offline + * periodically. Checks the incoming messages against the sent messages of + * the server. + */ + private final class DurableSubscriber { + + final ConnectionFactory cf = new ActiveMQConnectionFactory(connectionUri); + + private final String subName; + + private final int id; + private final String conClientId; + private final String selector; + + public DurableSubscriber(int id) throws JMSException { + this.id = id; + conClientId = "cli" + id; + subName = "subscription" + id; + selector = "RELEVANT = true"; + } + + private void process() throws JMSException { + long end = System.currentTimeMillis() + 20000; + int transCount = 0; + + LOG.info(toString() + " ONLINE."); + Connection con = openConnection(); + + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = sess.createDurableSubscriber(topic, subName, selector, false); + + try { + + do { + long max = end - System.currentTimeMillis(); + + if (max <= 0) { + break; + } + + Message message = consumer.receive(max); + if (message == null) { + continue; + } + + LOG.info("Received Trans[id=" + message.getIntProperty("TRANS") + ", count=" + transCount + "] in " + this + "."); + + } while (true); + + } finally { + sess.close(); + con.close(); + + LOG.info(toString() + " OFFLINE."); + } + } + + private Connection openConnection() throws JMSException { + Connection con = cf.createConnection(); + con.setClientID(conClientId); + con.start(); + return con; + } + + private void unsubscribe() throws JMSException { + Connection con = openConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe(subName); + session.close(); + con.close(); + } + + @Override + public String toString() { + return "DurableSubscriber[id=" + id + "]"; + } + } + + @Before + public void setUp() throws Exception { + topic = new ActiveMQTopic("TopicT"); + startBroker(); + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + private void startBroker() throws Exception { + startBroker(true); + } + + private void startBroker(boolean deleteAllMessages) throws Exception { + if (broker != null) + return; + + broker = BrokerFactory.createBroker("broker:(vm://" + getName() + ")"); + broker.setBrokerName(getName()); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + + File kahadbData = new File("activemq-data/" + getName() + "-kahadb"); + if (deleteAllMessages) + delete(kahadbData); + + broker.setPersistent(true); + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setDirectory(kahadbData); + kahadb.setJournalMaxFileLength(500 * 1024); + broker.setPersistenceAdapter(kahadb); + + connectionUri = broker.addConnector("tcp://localhost:0").getPublishableConnectString(); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getTempUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getStoreUsage().setLimit(256 * 1024 * 1024); + + broker.start(); + } + + protected static String getName() { + return "DurableSubSelectorDelayTest"; + } + + private static boolean delete(File path) { + if (path == null) + return true; + + if (path.isDirectory()) { + for (File file : path.listFiles()) { + delete(file); + } + } + return path.delete(); + } + + private void destroyBroker() throws Exception { + if (broker == null) + return; + + broker.stop(); + broker = null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubSelectorDelayWithRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubSelectorDelayWithRestartTest.java new file mode 100644 index 0000000000..5e1cb429ba --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubSelectorDelayWithRestartTest.java @@ -0,0 +1,342 @@ +/** + * 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 ONDITIONS 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.usecases; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubSelectorDelayWithRestartTest { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubSelectorDelayWithRestartTest.class); + + public static final long RUNTIME = 1 * 60 * 1000; + + private boolean RESTART = true; + private int NUMBER_SUBSCRIBERS = 3; + + private BrokerService broker; + private ActiveMQTopic topic; + + @Test + public void testProcess() throws Exception { + + MsgProducer msgProducer = new MsgProducer(); + msgProducer.start(); + + DurableSubscriber subscribers[] = new DurableSubscriber[NUMBER_SUBSCRIBERS]; + + for (int i = 0; i < subscribers.length - 1; i++) { + subscribers[i] = new DurableSubscriber(i); + subscribers[i].process(); + } + + // wait for server to finish + msgProducer.join(); + + //for the last subscriber pop one message into the topic. + subscribers[(subscribers.length - 1)] = new DurableSubscriber((subscribers.length - 1)); + subscribers[(subscribers.length - 1)].subscribe(); + MsgProducer msgProducer2 = new MsgProducer(); + msgProducer2.send(); + subscribers[(subscribers.length - 1)].process(); + + // unsubscribe all, but the last subscriber. + for (int j = 0; j < (subscribers.length - 1); j++) { + LOG.info("Unsubscribing subscriber " + subscribers[j]); + subscribers[j].unsubscribe(); + } + + final KahaDBPersistenceAdapter pa = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + assertTrue("small number of journal files should be left ", Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + LOG.info("journal data file count - expected {} actual {}", 4, pa.getStore().getJournal().getFileMap().size()); + return pa.getStore().getJournal().getFileMap().size() < 4; + } + }, TimeUnit.MINUTES.toMillis(3))); + + LOG.info("DONE."); + } + + /** + * Message Producer + */ + final class MsgProducer extends Thread { + + final String url = "failover:(tcp://localhost:61656)"; + + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + int transRover = 0; + int messageRover = 0; + + public MsgProducer() { + super("MsgProducer"); + setDaemon(true); + } + + @Override + public void run() { + long endTime = RUNTIME + System.currentTimeMillis(); + + try { + while (endTime > System.currentTimeMillis()) { + Thread.sleep(400); + send(); + + //restart broker all the time + if(RESTART){ + destroyBroker(); + startBroker(false); + } + } + } catch (Throwable e) { + e.printStackTrace(System.out); + throw new RuntimeException(e); + } + } + + public void send() throws JMSException { + + int trans = ++transRover; + boolean relevantTrans = true; + int count = 40; + + LOG.info("Sending Trans[id=" + trans + ", count=" + + count + "]"); + + Connection con = cf.createConnection(); + + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer prod = sess.createProducer(null); + + for (int i = 0; i < count; i++) { + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("RELEVANT", false); + prod.send(topic, message); + } + + Message message = sess.createMessage(); + message.setIntProperty("ID", ++messageRover); + message.setIntProperty("TRANS", trans); + message.setBooleanProperty("COMMIT", true); + message.setBooleanProperty("RELEVANT", relevantTrans); + prod.send(topic, message); + + LOG.info("Committed Trans[id=" + trans + ", count=" + + count + "], ID=" + messageRover); + + sess.close(); + con.close(); + } + } + + /** + * Consumes massages from a durable subscription. Goes online/offline + * periodically. Checks the incoming messages against the sent messages of + * the server. + */ + private final class DurableSubscriber { + + final String url = "failover:(tcp://localhost:61656)"; + + final ConnectionFactory cf = new ActiveMQConnectionFactory(url); + + private final String subName ; + + private final int id; + private final String conClientId; + private final String selector; + + public DurableSubscriber(int id) throws JMSException { + this.id = id; + conClientId = "cli" + id; + subName = "subscription"+ id; + selector ="RELEVANT = true"; + } + + private void process() throws JMSException { + long end = System.currentTimeMillis() + 20000; + int transCount = 0; + + LOG.info(toString() + " ONLINE."); + Connection con = openConnection(); + + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = sess.createDurableSubscriber(topic, subName, selector, false); + + try { + + do { + long max = end - System.currentTimeMillis(); + + if (max <= 0) { + break; + } + + Message message = consumer.receive(max); + if (message == null) { + continue; + } + + LOG.info("Received Trans[id=" + + message.getIntProperty("TRANS") + ", count=" + + transCount + "] in " + this + "."); + + } while (true); + + } finally { + try { + sess.close(); + con.close(); + } catch (Exception e) {} + + LOG.info(toString() + " OFFLINE."); + } + } + + private Connection openConnection() throws JMSException { + Connection con = cf.createConnection(); + con.setClientID(conClientId); + con.start(); + return con; + } + + public void subscribe() throws JMSException{ + LOG.info(toString() + "SUBSCRIBING"); + Connection con = openConnection(); + + Session sess = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + sess.createDurableSubscriber(topic, subName, selector, false); + + sess.close(); + con.close(); + } + + private void unsubscribe() throws JMSException { + Connection con = openConnection(); + Session session = con + .createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe(subName); + session.close(); + con.close(); + } + + @Override + public String toString() { + return "DurableSubscriber[id=" + id + "]"; + } + } + + @Before + public void setUp() throws Exception { + topic = new ActiveMQTopic("TopicT"); + startBroker(); + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + private void startBroker() throws Exception { + startBroker(true); + } + + private void startBroker(boolean deleteAllMessages) throws Exception { + if (broker != null) + return; + + broker = BrokerFactory.createBroker("broker:(vm://" + getName() + ")"); + broker.setBrokerName(getName()); + broker.setAdvisorySupport(false); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + + File kahadbData = new File("activemq-data/" + getName() + "-kahadb"); + if (deleteAllMessages) + delete(kahadbData); + + broker.setPersistent(true); + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setDirectory(kahadbData); + kahadb.setJournalMaxFileLength( 10 * 1024); + kahadb.setCleanupInterval(5000); + broker.setPersistenceAdapter(kahadb); + + broker.addConnector("tcp://localhost:61656"); + + broker.getSystemUsage().getMemoryUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getTempUsage().setLimit(256 * 1024 * 1024); + broker.getSystemUsage().getStoreUsage().setLimit(256 * 1024 * 1024); + + LOG.info(toString() + "Starting Broker..."); + broker.start(); + broker.waitUntilStarted(); + + LOG.info(toString() + " Broker started!!"); + } + + protected static String getName() { + return "DurableSubSelectorDelayTest"; + } + + private static boolean delete(File path) { + if (path == null) + return true; + + if (path.isDirectory()) { + for (File file : path.listFiles()) { + delete(file); + } + } + return path.delete(); + } + + private void destroyBroker() throws Exception { + if (broker == null) + return; + + broker.stop(); + broker = null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubsOfflineSelectorConcurrentConsumeIndexUseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubsOfflineSelectorConcurrentConsumeIndexUseTest.java new file mode 100644 index 0000000000..0afc8da7a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubsOfflineSelectorConcurrentConsumeIndexUseTest.java @@ -0,0 +1,257 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubsOfflineSelectorConcurrentConsumeIndexUseTest extends org.apache.activemq.TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubsOfflineSelectorConcurrentConsumeIndexUseTest.class); + public int messageCount = 10000; + private BrokerService broker; + private ActiveMQTopic topic; + private final List exceptions = new ArrayList(); + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); + connectionFactory.setWatchTopicAdvisories(false); + return connectionFactory; + } + + @Override + protected Connection createConnection() throws Exception { + return createConnection("id"); + } + + protected Connection createConnection(String name) throws Exception { + Connection con = getConnectionFactory().createConnection(); + con.setClientID(name); + con.start(); + return con; + } + + public static Test suite() { + return suite(DurableSubsOfflineSelectorConcurrentConsumeIndexUseTest.class); + } + + @Override + protected void setUp() throws Exception { + exceptions.clear(); + topic = (ActiveMQTopic) createDestination(); + createBroker(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + private void createBroker() throws Exception { + createBroker(true); + } + + private void createBroker(boolean deleteAllMessages) throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://" + getName(true) + ")"); + broker.setBrokerName(getName(true)); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + broker.getManagementContext().setCreateConnector(false); + broker.setAdvisorySupport(false); + broker.addConnector("tcp://0.0.0.0:0"); + + setDefaultPersistenceAdapter(broker); + + ((KahaDBPersistenceAdapter)broker.getPersistenceAdapter()).getStore().getPageFile().setPageSize(1024); + + broker.start(); + } + + private void destroyBroker() throws Exception { + if (broker != null) + broker.stop(); + } + + public void testIndexPageUsage() throws Exception { + Connection con = createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "true", "filter = 'true'", true); + session.close(); + + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "false", "filter = 'false'", true); + session.close(); + + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "all", null, true); + session.close(); + + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "all2", null, true); + session.close(); + + con.close(); + + // send messages + + final CountDownLatch goOn = new CountDownLatch(1); + Thread sendThread = new Thread() { + @Override + public void run() { + try { + + final Connection sendCon = createConnection("send"); + final Session sendSession = sendCon.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = sendSession.createProducer(null); + + for (int i = 0; i < messageCount; i++) { + boolean filter = i % 2 == 1; + Message message = sendSession.createMessage(); + message.setStringProperty("filter", filter ? "true" : "false"); + producer.send(topic, message); + + if (i > 0 && i % 10000 == 0) { + LOG.info("Sent:" + i); + } + if (i> messageCount/2) { + goOn.countDown(); + } + } + sendSession.close(); + sendCon.close(); + } catch (Exception e) { + exceptions.add(e); + } + } + }; + sendThread.start(); + + goOn.await(5, TimeUnit.MINUTES); + LOG.info("Activating consumers"); + + // consume messages in parallel + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumerTrue = session.createDurableSubscriber(topic, "true", "filter = 'true'", true); + Listener listenerT = new Listener(); + consumerTrue.setMessageListener(listenerT); + + MessageConsumer consumerFalse = session.createDurableSubscriber(topic, "false", "filter = 'false'", true); + Listener listenerF = new Listener(); + consumerFalse.setMessageListener(listenerF); + + MessageConsumer consumerAll = session.createDurableSubscriber(topic, "all", null, true); + Listener listenerA = new Listener(); + consumerAll.setMessageListener(listenerA); + + MessageConsumer consumerAll2 = session.createDurableSubscriber(topic, "all2", null, true); + Listener listenerA2 = new Listener(); + consumerAll2.setMessageListener(listenerA2); + + waitFor(listenerA, messageCount); + assertEquals(messageCount, listenerA.count); + + waitFor(listenerA2, messageCount); + assertEquals(messageCount, listenerA2.count); + + assertEquals(messageCount / 2, listenerT.count); + assertEquals(messageCount / 2, listenerF.count); + + consumerTrue.close(); + session.unsubscribe("true"); + + consumerFalse.close(); + session.unsubscribe("false"); + + consumerAll.close(); + session.unsubscribe("all"); + + session.close(); + con.close(); + + PersistenceAdapter persistenceAdapter = broker.getPersistenceAdapter(); + if( persistenceAdapter instanceof KahaDBPersistenceAdapter) { + final KahaDBStore store = ((KahaDBPersistenceAdapter) persistenceAdapter).getStore(); + LOG.info("Store page count: " + store.getPageFile().getPageCount()); + LOG.info("Store free page count: " + store.getPageFile().getFreePageCount()); + LOG.info("Store page in-use: " + (store.getPageFile().getPageCount() - store.getPageFile().getFreePageCount())); + + assertTrue("no leak of pages, always use just 11", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 11 == store.getPageFile().getPageCount() - + store.getPageFile().getFreePageCount(); + } + }, TimeUnit.SECONDS.toMillis(10))); + } + } + + private void waitFor(final Listener listener, final int count) throws Exception { + + assertTrue("got all messages on time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return listener.count == count; + } + }, TimeUnit.MINUTES.toMillis(10))); + + } + + public static class Listener implements MessageListener { + int count = 0; + String id = null; + + Listener() { + } + + @Override + public void onMessage(Message message) { + count++; + if (id != null) { + try { + LOG.info(id + ", " + message.getJMSMessageID()); + } catch (Exception ignored) { + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubsOfflineSelectorIndexUseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubsOfflineSelectorIndexUseTest.java new file mode 100644 index 0000000000..e25a30c009 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubsOfflineSelectorIndexUseTest.java @@ -0,0 +1,225 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubsOfflineSelectorIndexUseTest extends org.apache.activemq.TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubsOfflineSelectorIndexUseTest.class); + public int messageCount = 400; + private BrokerService broker; + private ActiveMQTopic topic; + private List exceptions = new ArrayList(); + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); + connectionFactory.setWatchTopicAdvisories(false); + return connectionFactory; + } + + @Override + protected Connection createConnection() throws Exception { + return createConnection("id"); + } + + protected Connection createConnection(String name) throws Exception { + Connection con = super.createConnection(); + con.setClientID(name); + con.start(); + return con; + } + + public static Test suite() { + return suite(DurableSubsOfflineSelectorIndexUseTest.class); + } + + protected void setUp() throws Exception { + exceptions.clear(); + topic = (ActiveMQTopic) createDestination(); + createBroker(); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + private void createBroker() throws Exception { + createBroker(true); + } + + private void createBroker(boolean deleteAllMessages) throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://" + getName(true) + ")"); + broker.setBrokerName(getName(true)); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + broker.getManagementContext().setCreateConnector(false); + broker.setAdvisorySupport(false); + broker.addConnector("tcp://0.0.0.0:0"); + + setDefaultPersistenceAdapter(broker); + broker.start(); + } + + private void destroyBroker() throws Exception { + if (broker != null) + broker.stop(); + } + + public void initCombosForTestIndexPageUsage() { + addCombinationValues("messageCount", new Integer[]{890, 900, 400}); + } + + public void testIndexPageUsage() throws Exception { + Connection con = createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "true", "filter = 'true'", true); + session.close(); + + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "false", "filter = 'false'", true); + session.close(); + + con.close(); + + // send messages + final Connection sendCon = createConnection("send"); + final Session sendSession = sendCon.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = sendSession.createProducer(null); + + Thread sendThread = new Thread() { + public void run() { + try { + + for (int i = 0; i < messageCount; i++) { + boolean filter = i % 2 == 1; + Message message = sendSession.createMessage(); + message.setStringProperty("filter", filter ? "true" : "false"); + producer.send(topic, message); + + if (i > 0 && i % 1000 == 0) { + LOG.info("Sent:" + i); + } + } + sendSession.close(); + sendCon.close(); + } catch (Exception e) { + exceptions.add(e); + } + } + }; + sendThread.start(); + + sendThread.join(); + + // settle with sent messages + TimeUnit.SECONDS.sleep(4); + + // consume messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumerTrue = session.createDurableSubscriber(topic, "true", "filter = 'true'", true); + Listener listenerT = new Listener(); + consumerTrue.setMessageListener(listenerT); + + waitFor(listenerT, messageCount / 2); + + MessageConsumer consumerFalse = session.createDurableSubscriber(topic, "false", "filter = 'false'", true); + Listener listenerF = new Listener(); + consumerFalse.setMessageListener(listenerF); + + waitFor(listenerF, messageCount / 2); + + assertEquals(messageCount / 2, listenerT.count); + assertEquals(messageCount / 2, listenerF.count); + + consumerTrue.close(); + session.unsubscribe("true"); + + consumerFalse.close(); + session.unsubscribe("false"); + + session.close(); + con.close(); + + PersistenceAdapter persistenceAdapter = broker.getPersistenceAdapter(); + if( persistenceAdapter instanceof KahaDBStore) { + final KahaDBStore store = ((KahaDBPersistenceAdapter) persistenceAdapter).getStore(); + LOG.info("Store page count: " + store.getPageFile().getPageCount()); + LOG.info("Store free page count: " + store.getPageFile().getFreePageCount()); + LOG.info("Store page in-use: " + (store.getPageFile().getPageCount() - store.getPageFile().getFreePageCount())); + + assertTrue("no leak of pages, always use just 10", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 10 == store.getPageFile().getPageCount() - + store.getPageFile().getFreePageCount(); + } + }, TimeUnit.SECONDS.toMillis(10))); + } + } + + private void waitFor(final Listener listener, final int count) throws Exception { + + assertTrue("got all messages on time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return listener.count == count; + } + }, TimeUnit.MINUTES.toMillis(10))); + + } + + public static class Listener implements MessageListener { + int count = 0; + String id = null; + + Listener() { + } + + public void onMessage(Message message) { + count++; + if (id != null) { + try { + LOG.info(id + ", " + message.getJMSMessageID()); + } catch (Exception ignored) { + } + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberNonPersistentMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberNonPersistentMessageTest.java new file mode 100644 index 0000000000..74f6664dec --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberNonPersistentMessageTest.java @@ -0,0 +1,322 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.management.ManagementFactory; +import java.util.Date; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubscriberNonPersistentMessageTest extends TestCase { + + private final Logger LOG = LoggerFactory.getLogger(DurableSubscriberNonPersistentMessageTest.class); + private String brokerURL; + private String consumerBrokerURL; + + int initialMaxMsgs = 10; + int cleanupMsgCount = 10; + int totalMsgCount = initialMaxMsgs + cleanupMsgCount; + int totalMsgReceived = 0; + int sleep = 500; + int reconnectSleep = 2000; + int messageTimeout = 1000; + int messageSize = 1024; + + // Note: If ttl is set 0, the default set by the broker will be used if any + // setting a value greater than 0 will enable the producer to set the ttl on + // the message + long ttl = 0; + + static String clientId = "Jason"; + MBeanServer mbeanServer; + + BrokerService broker; + + @Override + protected void setUp() throws Exception { + super.setUp(); + broker = new BrokerService(); + TransportConnector transportConnector = broker.addConnector("tcp://localhost:0"); + KahaDBStore store = new KahaDBStore(); + store.setDirectory(new File("data")); + broker.setPersistenceAdapter(store); + broker.start(); + + brokerURL = "failover:(" + transportConnector.getPublishableConnectString() + ")"; + consumerBrokerURL = brokerURL + "?jms.prefetchPolicy.all=100"; + + mbeanServer = ManagementFactory.getPlatformMBeanServer(); + } + + @Override + protected void tearDown() throws Exception { + broker.stop(); + super.tearDown(); + } + + /** + * Create the test case + * + * @param testName + * name of the test case + */ + public DurableSubscriberNonPersistentMessageTest(String testName) { + super(testName); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() { + return new TestSuite(DurableSubscriberNonPersistentMessageTest.class); + } + + public void testDurableSubscriberNonPersistentMessage() { + String interest = "TEST"; + + LOG.info("Starting DurableSubscriberNonPersistentMessageTest"); + + try { + // create durable topic consumer and disconnect + createConsumer(interest, 0); + Thread.sleep(1000); + + // produce 15 messages to topic + Producer producer = new Producer(brokerURL, interest, messageSize, ttl); + producer.sendMessages(totalMsgCount); + producer.close(); + LOG.info(totalMsgCount + " messages sent"); + + // durable topic consumer will consume 10 messages and disconnect + createConsumer(interest, initialMaxMsgs); + + Thread.sleep(reconnectSleep); + + createConsumer(interest, cleanupMsgCount); + + String brokerVersion = (String) mbeanServer.getAttribute(new ObjectName("org.apache.activemq:brokerName=localhost,type=Broker"), "BrokerVersion"); + + LOG.info("Test run on: " + brokerVersion); + final String theJmxObject = "org.apache.activemq:type=Broker,brokerName=localhost," + + "endpoint=Consumer,destinationType=Topic,destinationName=TEST,clientId=Jason," + + "consumerId=Durable(Jason_MyDurableTopic)"; + + assertTrue("pendingQueueSize should be zero", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Integer pendingQueueSize = (Integer) mbeanServer.getAttribute(new ObjectName(theJmxObject), "PendingQueueSize"); + LOG.info("pendingQueueSize = " + pendingQueueSize); + return pendingQueueSize.intValue() == 0; + } + })); + + assertTrue("cursorMemoryUsage should be zero", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Long cursorMemoryUsage = (Long) mbeanServer.getAttribute(new ObjectName(theJmxObject), "CursorMemoryUsage"); + LOG.info("cursorMemoryUsage = " + cursorMemoryUsage); + return cursorMemoryUsage.longValue() == 0L; + } + })); + + // Not sure what the behavior should be here, if the messages + // expired the received count shouldn't equal total message count + assertTrue(totalMsgReceived == initialMaxMsgs + cleanupMsgCount); + } catch (Exception e) { + LOG.error("Exception Executing DurableSubscriberNonPersistentMessageTest: " + getStackTrace(e)); + fail("Should not throw any exceptions"); + } + } + + // create durable topic consumer and max number of messages + public void createConsumer(String interest, int maxMsgs) { + int messageReceived = 0; + int messagesNotReceived = 0; + + LOG.info("Starting DurableSubscriber"); + + Consumer consumer = null; + + try { + consumer = new Consumer(consumerBrokerURL, interest, clientId); + + for (int i = 0; i < maxMsgs; i++) { + try { + Message msg = consumer.getMessage(messageTimeout); + if (msg != null) { + LOG.debug("Received Message: " + msg.toString()); + messageReceived++; + totalMsgReceived++; + } else { + LOG.debug("message " + i + " not received"); + messagesNotReceived++; + } + + Thread.sleep(sleep); + } catch (InterruptedException ie) { + LOG.debug("Exception: " + ie); + } + } + + consumer.close(); + + LOG.info("Consumer Finished"); + LOG.info("Received " + messageReceived); + LOG.info("Not Received " + messagesNotReceived); + } catch (JMSException e) { + LOG.error("Exception Executing SimpleConsumer: " + getStackTrace(e)); + } + } + + public String getStackTrace(Throwable aThrowable) { + final Writer result = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(result); + aThrowable.printStackTrace(printWriter); + return result.toString(); + } + + public class Producer { + + protected ConnectionFactory factory; + protected transient Connection connection; + protected transient Session session; + protected transient MessageProducer producer; + protected static final int messageSize = 1024; + + public Producer(String brokerURL, String interest, int messageSize, long ttl) throws JMSException { + + factory = new ActiveMQConnectionFactory(brokerURL); + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(session.createTopic(interest)); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + if (ttl > 0) { + producer.setTimeToLive(ttl); + } + } + + public void close() throws JMSException { + if (connection != null) { + connection.close(); + } + } + + protected void sendMessage() throws JMSException { + TextMessage textMessage = session.createTextMessage("test message"); + producer.send(textMessage); + } + + protected void sendMessages(int count) throws JMSException { + for (int i = 0; i < count; i++) { + TextMessage textMessage = session.createTextMessage(createMessageText(i)); + producer.send(textMessage); + } + } + + private String createMessageText(int index) { + StringBuffer buffer = new StringBuffer(messageSize); + buffer.append("Message: " + index + " sent at: " + new Date()); + if (buffer.length() > messageSize) { + return buffer.substring(0, messageSize); + } + for (int i = buffer.length(); i < messageSize; i++) { + buffer.append(' '); + } + return buffer.toString(); + } + + protected void commitTransaction() throws JMSException { + session.commit(); + } + } + + public class Consumer { + + private final ConnectionFactory factory; + private final ActiveMQConnection connection; + private final Session session; + private final MessageConsumer messageConsumer; + + public Consumer(String brokerURL, String interest, String clientId) throws JMSException { + factory = new ActiveMQConnectionFactory(brokerURL); + connection = (ActiveMQConnection) factory.createConnection(); + connection.setClientID(clientId); + connection.start(); + connection.getPrefetchPolicy().setAll(15); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createTopic(interest); + messageConsumer = session.createDurableSubscriber((Topic) destination, "MyDurableTopic"); + } + + public void deleteAllMessages() throws JMSException { + while (getMessage(500) != null) { + // empty queue + } + } + + public Message getMessage(int timeout) throws JMSException { + return messageConsumer.receive(timeout); + } + + public void close() throws JMSException { + if (messageConsumer != null) { + messageConsumer.close(); + } + if (session != null) { + session.close(); + } + if (connection != null) { + connection.close(); + } + } + + public Session getSession() { + return session; + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberWithNetworkDisconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberWithNetworkDisconnectTest.java new file mode 100644 index 0000000000..147d29566d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberWithNetworkDisconnectTest.java @@ -0,0 +1,234 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.List; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.SocketProxy; +import org.apache.activemq.util.Wait; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +public class DurableSubscriberWithNetworkDisconnectTest extends JmsMultipleBrokersTestSupport { + private static final Log LOG = LogFactory.getLog(DurableSubscriberWithNetworkDisconnectTest.class); + private static final int NETWORK_DOWN_TIME = 10000; + private static final String HUB = "HubBroker"; + private static final String SPOKE = "SpokeBroker"; + private SocketProxy socketProxy; + private long networkDownTimeStart; + private long inactiveDuration = 1000; + private long receivedMsgs = 0; + private boolean useSocketProxy = true; + protected static final int MESSAGE_COUNT = 200; + public boolean useDuplexNetworkBridge = true; + public boolean simulateStalledNetwork; + public boolean dynamicOnly = true; + public long networkTTL = 3; + public boolean exponentialBackOff; + public boolean failover = false; + public boolean inactivity = true; + + public void initCombosForTestSendOnAReceiveOnBWithTransportDisconnect() { + addCombinationValues("failover", new Object[]{Boolean.FALSE, Boolean.TRUE}); + } + + public void testSendOnAReceiveOnBWithTransportDisconnect() throws Exception { + bridgeBrokers(SPOKE, HUB); + + startAllBrokers(); + + // Setup connection + URI hubURI = brokers.get(HUB).broker.getVmConnectorURI(); + URI spokeURI = brokers.get(SPOKE).broker.getVmConnectorURI(); + ActiveMQConnectionFactory facHub = new ActiveMQConnectionFactory(hubURI); + ActiveMQConnectionFactory facSpoke = new ActiveMQConnectionFactory(spokeURI); + Connection conHub = facHub.createConnection(); + Connection conSpoke = facSpoke.createConnection(); + conHub.setClientID("clientHUB"); + conSpoke.setClientID("clientSPOKE"); + conHub.start(); + conSpoke.start(); + Session sesHub = conHub.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session sesSpoke = conSpoke.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQTopic topic = new ActiveMQTopic("TEST.FOO"); + String consumerName = "consumerName"; + + // Setup consumers + MessageConsumer remoteConsumer = sesSpoke.createDurableSubscriber(topic, consumerName); + remoteConsumer.setMessageListener(new MessageListener() { + public void onMessage(Message msg) { + try { + TextMessage textMsg = (TextMessage) msg; + receivedMsgs++; + LOG.info("Received messages (" + receivedMsgs + "): " + textMsg.getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + } + }); + + // allow subscription information to flow back to Spoke + sleep(1000); + + // Setup producer + MessageProducer localProducer = sesHub.createProducer(topic); + localProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + + // Send messages + for (int i = 0; i < MESSAGE_COUNT; i++) { + sleep(50); + if (i == 50 || i == 150) { + if (simulateStalledNetwork) { + socketProxy.pause(); + } else { + socketProxy.close(); + } + networkDownTimeStart = System.currentTimeMillis(); + } else if (networkDownTimeStart > 0) { + // restart after NETWORK_DOWN_TIME seconds + sleep(NETWORK_DOWN_TIME); + networkDownTimeStart = 0; + if (simulateStalledNetwork) { + socketProxy.goOn(); + } else { + socketProxy.reopen(); + } + } else { + // slow message production to allow bridge to recover and limit message duplication + sleep(500); + } + Message test = sesHub.createTextMessage("test-" + i); + localProducer.send(test); + } + + LOG.info("waiting for messages to flow"); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return receivedMsgs >= MESSAGE_COUNT; + } + }); + + assertTrue("At least message " + MESSAGE_COUNT + + " must be received, count=" + receivedMsgs, + MESSAGE_COUNT <= receivedMsgs); + brokers.get(HUB).broker.deleteAllMessages(); + brokers.get(SPOKE).broker.deleteAllMessages(); + conHub.close(); + conSpoke.close(); + } + + @Override + protected void startAllBrokers() throws Exception { + // Ensure HUB is started first so bridge will be active from the get go + BrokerItem brokerItem = brokers.get(HUB); + brokerItem.broker.start(); + brokerItem = brokers.get(SPOKE); + brokerItem.broker.start(); + sleep(600); + } + + public void setUp() throws Exception { + networkDownTimeStart = 0; + inactiveDuration = 1000; + useSocketProxy = true; + receivedMsgs = 0; + super.setAutoFail(true); + super.setUp(); + final String options = "?persistent=true&useJmx=false&deleteAllMessagesOnStartup=true"; + createBroker(new URI("broker:(tcp://localhost:61617)/" + HUB + options)); + createBroker(new URI("broker:(tcp://localhost:61616)/" + SPOKE + options)); + } + + public void tearDown() throws Exception { + super.tearDown(); + if (socketProxy != null) { + socketProxy.close(); + } + } + + public static Test suite() { + return suite(DurableSubscriberWithNetworkDisconnectTest.class); + } + + private void sleep(int milliSecondTime) { + try { + Thread.sleep(milliSecondTime); + } catch (InterruptedException igonred) { + } + } + + @Override + protected NetworkConnector bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker, boolean l_dynamicOnly, int networkTTL, boolean l_conduit, boolean l_failover) throws Exception { + List transportConnectors = remoteBroker.getTransportConnectors(); + URI remoteURI; + if (!transportConnectors.isEmpty()) { + remoteURI = ((TransportConnector) transportConnectors.get(0)).getConnectUri(); + if (useSocketProxy) { + socketProxy = new SocketProxy(remoteURI); + remoteURI = socketProxy.getUrl(); + } + String options = ""; + if (failover) { + options = "static:(failover:(" + remoteURI; + } else { + options = "static:(" + remoteURI; + } + if (inactivity) { + options += "?wireFormat.maxInactivityDuration=" + inactiveDuration + "&wireFormat.maxInactivityDurationInitalDelay=" + inactiveDuration + ")"; + } else { + options += ")"; + } + + if (failover) { + options += "?maxReconnectAttempts=0)"; + } + + options += "?useExponentialBackOff=" + exponentialBackOff; + DiscoveryNetworkConnector connector = new DiscoveryNetworkConnector(new URI(options)); + connector.setDynamicOnly(dynamicOnly); + connector.setNetworkTTL(networkTTL); + localBroker.addNetworkConnector(connector); + maxSetupTime = 2000; + if (useDuplexNetworkBridge) { + connector.setDuplex(true); + } + return connector; + } else { + throw new Exception("Remote broker has no registered connectors."); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberWithNetworkRestartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberWithNetworkRestartTest.java new file mode 100644 index 0000000000..3799c6cc7a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriberWithNetworkRestartTest.java @@ -0,0 +1,231 @@ +/** + * 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.usecases; + +import java.net.MalformedURLException; +import java.net.URI; +import java.util.Set; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import static org.junit.Assume.assumeNotNull; + + +public class DurableSubscriberWithNetworkRestartTest extends JmsMultipleBrokersTestSupport { + private static final Log LOG = LogFactory.getLog(DurableSubscriberWithNetworkRestartTest.class); + private static final String HUB = "HubBroker"; + private static final String SPOKE = "SpokeBroker"; + protected static final int MESSAGE_COUNT = 10; + public boolean dynamicOnly = false; + + public void testSendOnAReceiveOnBWithTransportDisconnectDynamicOnly() throws Exception { + dynamicOnly = true; + try { + testSendOnAReceiveOnBWithTransportDisconnect(); + } finally { + dynamicOnly = false; + } + } + + public void testSendOnAReceiveOnBWithTransportDisconnect() throws Exception { + bridge(SPOKE, HUB); + startAllBrokers(); + + verifyDuplexBridgeMbean(); + + // Setup connection + URI hubURI = brokers.get(HUB).broker.getTransportConnectors().get(0).getPublishableConnectURI(); + URI spokeURI = brokers.get(SPOKE).broker.getTransportConnectors().get(0).getPublishableConnectURI(); + ActiveMQConnectionFactory facHub = new ActiveMQConnectionFactory(hubURI); + ActiveMQConnectionFactory facSpoke = new ActiveMQConnectionFactory(spokeURI); + Connection conHub = facHub.createConnection(); + Connection conSpoke = facSpoke.createConnection(); + conHub.setClientID("clientHUB"); + conSpoke.setClientID("clientSPOKE"); + conHub.start(); + conSpoke.start(); + Session sesHub = conHub.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session sesSpoke = conSpoke.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ActiveMQTopic topic = new ActiveMQTopic("TEST.FOO"); + String consumerName = "consumerName"; + + // Setup consumers + MessageConsumer remoteConsumer = sesHub.createDurableSubscriber(topic, consumerName); + sleep(1000); + remoteConsumer.close(); + + // Setup producer + MessageProducer localProducer = sesSpoke.createProducer(topic); + localProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + + final String payloadString = new String(new byte[10*1024]); + // Send messages + for (int i = 0; i < MESSAGE_COUNT; i++) { + Message test = sesSpoke.createTextMessage("test-" + i); + test.setStringProperty("payload", payloadString); + localProducer.send(test); + } + localProducer.close(); + + final String options = "?persistent=true&useJmx=true&deleteAllMessagesOnStartup=false"; + for (int i=0;i<2;i++) { + brokers.get(SPOKE).broker.stop(); + sleep(1000); + createBroker(new URI("broker:(tcp://localhost:61616)/" + SPOKE + options)); + bridge(SPOKE, HUB); + brokers.get(SPOKE).broker.start(); + LOG.info("restarted spoke..:" + i); + + assertTrue("got mbeans on restart", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return countMbeans( brokers.get(HUB).broker, "networkBridge", 20000) == (dynamicOnly ? 1 : 2); + } + })); + } + } + + private void verifyDuplexBridgeMbean() throws Exception { + assertEquals(1, countMbeans( brokers.get(HUB).broker, "networkBridge", 5000)); + } + + private int countMbeans(BrokerService broker, String type, int timeout) throws Exception { + final long expiryTime = System.currentTimeMillis() + timeout; + + if (!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); + } + + mbeans = broker.getManagementContext().queryNames(beanName, null); + if (mbeans != null) { + count = mbeans.size(); + LOG.info("Found: " + count + ", matching type: " +type); + for (ObjectName objectName : mbeans) { + LOG.info("" + objectName); + } + //} 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) { + assumeNotNull(mbeans); + } + + return count; + + } + + private void logAllMbeans(BrokerService broker) throws MalformedURLException { + try { + // trace all existing MBeans + Set all = broker.getManagementContext().queryNames(null, null); + LOG.info("Total MBean count=" + all.size()); + for (Object o : all) { + //ObjectInstance bean = (ObjectInstance)o; + LOG.info(o); + } + } catch (Exception ignored) { + LOG.warn("getMBeanServer ex: " + ignored); + } + } + + public NetworkConnector bridge(String from, String to) throws Exception { + NetworkConnector networkConnector = bridgeBrokers(from, to, dynamicOnly, -1, true); + networkConnector.setSuppressDuplicateQueueSubscriptions(true); + networkConnector.setDecreaseNetworkConsumerPriority(true); + networkConnector.setConsumerTTL(1); + networkConnector.setDuplex(true); + return networkConnector; + } + + @Override + protected void startAllBrokers() throws Exception { + // Ensure HUB is started first so bridge will be active from the get go + BrokerItem brokerItem = brokers.get(HUB); + brokerItem.broker.start(); + brokerItem = brokers.get(SPOKE); + brokerItem.broker.start(); + sleep(600); + } + + public void setUp() throws Exception { + super.setAutoFail(false); + super.setUp(); + createBrokers(true); + } + + private void createBrokers(boolean del) throws Exception { + final String options = "?persistent=true&useJmx=true&deleteAllMessagesOnStartup=" + del; + createBroker(new URI("broker:(tcp://localhost:61617)/" + HUB + options)); + createBroker(new URI("broker:(tcp://localhost:61616)/" + SPOKE + options)); + } + + protected void configureBroker(BrokerService broker) { + broker.setKeepDurableSubsActive(false); + broker.getManagementContext().setCreateConnector(false); + PolicyMap defaultPolcyMap = new PolicyMap(); + PolicyEntry defaultPolicy = new PolicyEntry(); + //defaultPolicy.setUseCache(false); + if (broker.getBrokerName().equals(HUB)) { + defaultPolicy.setStoreUsageHighWaterMark(2); + broker.getSystemUsage().getStoreUsage().setLimit(1*1024*1024); + } + defaultPolcyMap.setDefaultEntry(defaultPolicy); + broker.setDestinationPolicy(defaultPolcyMap); + broker.getSystemUsage().getMemoryUsage().setLimit(100*1024*1024); + } + + public void tearDown() throws Exception { + super.tearDown(); + } + + private void sleep(int milliSecondTime) { + try { + Thread.sleep(milliSecondTime); + } catch (InterruptedException igonred) { + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionActivationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionActivationTest.java new file mode 100644 index 0000000000..6156657081 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionActivationTest.java @@ -0,0 +1,122 @@ +/** + * 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.usecases; + +import java.io.File; + +import javax.jms.Connection; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; + +public class DurableSubscriptionActivationTest extends org.apache.activemq.TestSupport { + + private BrokerService broker; + private Connection connection; + private ActiveMQTopic topic; + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://" + getName()); + } + + protected Connection createConnection() throws Exception { + Connection rc = super.createConnection(); + rc.setClientID(getName()); + return rc; + } + + protected void setUp() throws Exception { + topic = (ActiveMQTopic) createDestination(); + createBroker(true); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + protected void restartBroker() throws Exception { + destroyBroker(); + createBroker(false); + } + + private void createBroker(boolean delete) throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://localhost)"); + broker.setKeepDurableSubsActive(true); + broker.setPersistent(true); + broker.setDeleteAllMessagesOnStartup(delete); + KahaDBPersistenceAdapter kahadb = new KahaDBPersistenceAdapter(); + kahadb.setDirectory(new File("activemq-data/" + getName() + "-kahadb")); + kahadb.setJournalMaxFileLength(500 * 1024); + broker.setPersistenceAdapter(kahadb); + broker.setBrokerName(getName()); + + // only if we pre-create the destinations + broker.setDestinations(new ActiveMQDestination[]{topic}); + + broker.start(); + broker.waitUntilStarted(); + + connection = createConnection(); + } + + private void destroyBroker() throws Exception { + if (connection != null) + connection.close(); + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + public void testActivateWithExistingTopic() throws Exception { + // create durable subscription + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId"); + + Destination d = broker.getDestination(topic); + assertTrue("More than one consumer found: " + d.getConsumers().size(), d.getConsumers().size() == 1); + + // restart the broker + restartBroker(); + + d = broker.getDestination(topic); + assertTrue("More than one consumer found: " + d.getConsumers().size(), d.getConsumers().size() == 1); + + // activate + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId"); + + assertTrue("More than one consumer found: " + d.getConsumers().size(), d.getConsumers().size() == 1); + + // re-activate + connection.close(); + connection = createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId"); + + assertTrue("More than one consumer found: " + d.getConsumers().size(), d.getConsumers().size() == 1); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionHangTestCase.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionHangTestCase.java new file mode 100644 index 0000000000..bef912a514 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionHangTestCase.java @@ -0,0 +1,135 @@ +/** + * 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.usecases; + +import java.util.concurrent.TimeUnit; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.commons.lang.RandomStringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertNotNull; + +public class DurableSubscriptionHangTestCase { + private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionHangTestCase.class); + final static String brokerName = "DurableSubscriptionHangTestCase"; + final static String clientID = "myId"; + private static final String topicName = "myTopic"; + private static final String durableSubName = "mySub"; + BrokerService brokerService; + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setBrokerName(brokerName); + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setExpireMessagesPeriod(5000); + policyMap.setDefaultEntry(defaultEntry); + brokerService.setDestinationPolicy(policyMap); + brokerService.start(); + } + + @After + public void brokerStop() throws Exception { + brokerService.stop(); + } + + @Test + public void testHanging() throws Exception + { + registerDurableSubscription(); + produceExpiredAndOneNonExpiredMessages(); + TimeUnit.SECONDS.sleep(10); // make sure messages are expired + Message message = collectMessagesFromDurableSubscriptionForOneMinute(); + LOG.info("got message:" + message); + assertNotNull("Unable to read unexpired message", message); + } + + private void produceExpiredAndOneNonExpiredMessages() throws JMSException { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + brokerName); + TopicConnection connection = connectionFactory.createTopicConnection(); + TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic(topicName); + MessageProducer producer = session.createProducer(topic); + producer.setTimeToLive(TimeUnit.SECONDS.toMillis(1)); + for(int i=0; i<40000; i++) + { + sendRandomMessage(session, producer); + } + producer.setTimeToLive(TimeUnit.DAYS.toMillis(1)); + sendRandomMessage(session, producer); + connection.close(); + LOG.info("produceExpiredAndOneNonExpiredMessages done"); + } + + private void registerDurableSubscription() throws JMSException + { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + brokerName); + TopicConnection connection = connectionFactory.createTopicConnection(); + connection.setClientID(clientID); + TopicSession topicSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = topicSession.createTopic(topicName); + TopicSubscriber durableSubscriber = topicSession.createDurableSubscriber(topic, durableSubName); + connection.start(); + durableSubscriber.close(); + connection.close(); + LOG.info("Durable Sub Registered"); + } + + private Message collectMessagesFromDurableSubscriptionForOneMinute() throws Exception + { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + brokerName); + TopicConnection connection = connectionFactory.createTopicConnection(); + + connection.setClientID(clientID); + TopicSession topicSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = topicSession.createTopic(topicName); + connection.start(); + TopicSubscriber subscriber = topicSession.createDurableSubscriber(topic, durableSubName); + LOG.info("About to receive messages"); + Message message = subscriber.receive(120000); + subscriber.close(); + connection.close(); + LOG.info("collectMessagesFromDurableSubscriptionForOneMinute done"); + + return message; + } + + private void sendRandomMessage(TopicSession session, MessageProducer producer) throws JMSException { + TextMessage textMessage = session.createTextMessage(); + textMessage.setText(RandomStringUtils.random(500, "abcdefghijklmnopqrstuvwxyz")); + producer.send(textMessage); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline1Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline1Test.java new file mode 100644 index 0000000000..47fdac01d4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline1Test.java @@ -0,0 +1,247 @@ +/** + * 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.usecases; + +import org.apache.activemq.TestSupport.PersistenceAdapterChoice; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(value = Parameterized.class) +public class DurableSubscriptionOffline1Test extends DurableSubscriptionOfflineTestBase { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionOffline1Test.class); + + @Parameterized.Parameters(name = "{0}-{1}") + public static Collection getTestParameters() { + String osName = System.getProperty("os.name"); + LOG.debug("Running on [" + osName + "]"); + + List persistenceAdapterChoices = new ArrayList(); + + persistenceAdapterChoices.add(PersistenceAdapterChoice.KahaDB); + persistenceAdapterChoices.add(PersistenceAdapterChoice.JDBC); + if (!osName.equalsIgnoreCase("AIX") && !osName.equalsIgnoreCase("SunOS")) { + //choices.add(levelDb); + persistenceAdapterChoices.add(PersistenceAdapterChoice.LevelDB); + } + + List testParameters = new ArrayList(); + Boolean[] booleanValues = {Boolean.FALSE, Boolean.TRUE}; + List booleans = java.util.Arrays.asList(booleanValues); + for (Boolean booleanValue : booleans) { + for (PersistenceAdapterChoice persistenceAdapterChoice : persistenceAdapterChoices) { + Object[] currentChoice = {persistenceAdapterChoice, booleanValue}; + testParameters.add(currentChoice); + } + } + + return testParameters; + } + + public DurableSubscriptionOffline1Test(PersistenceAdapterChoice adapter, Boolean usePrioritySupport) { + this.defaultPersistenceAdapter = adapter; + this.usePrioritySupport = usePrioritySupport.booleanValue(); + LOG.debug(">>>> Created with adapter {} usePrioritySupport? {}", defaultPersistenceAdapter, usePrioritySupport); + + } + + @Test + public void testConsumeOnlyMatchedMessages() throws Exception { + // create durable subscription + Connection con = createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + int sent = 0; + for (int i = 0; i < 10; i++) { + boolean filter = i % 2 == 1; + if (filter) + sent++; + + Message message = session.createMessage(); + message.setStringProperty("filter", filter ? "true" : "false"); + producer.send(topic, message); + } + + session.close(); + con.close(); + + // consume messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals(sent, listener.count); + } + + @Test + public void testVerifyAllConsumedAreAcked() throws Exception { + // create durable subscription + Connection con = createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + 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(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + + session.close(); + con.close(); + + // consume messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + LOG.info("Consumed: " + listener.count); + assertEquals(sent, listener.count); + + // consume messages again, should not get any + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals(0, listener.count); + } + + @Test + public void testOfflineSubscriptionCanConsumeAfterOnlineSubs() throws Exception { + Connection con = createConnection("offCli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + con = createConnection("offCli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + Connection con2 = createConnection("onlineCli1"); + Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer2 = session2.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener2 = new DurableSubscriptionOfflineTestListener(); + consumer2.setMessageListener(listener2); + + // send messages + con = createConnection(); + 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(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + // test online subs + Thread.sleep(3 * 1000); + session2.close(); + con2.close(); + assertEquals(sent, listener2.count); + + // restart broker + broker.stop(); + createBroker(false /*deleteAllMessages*/); + + // test offline + con = createConnection("offCli1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + + Connection con3 = createConnection("offCli2"); + Session session3 = con3.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer3 = session3.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + DurableSubscriptionOfflineTestListener listener3 = new DurableSubscriptionOfflineTestListener(); + consumer3.setMessageListener(listener3); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + session3.close(); + con3.close(); + + assertEquals(sent, listener.count); + assertEquals(sent, listener3.count); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline2Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline2Test.java new file mode 100644 index 0000000000..960d9eaebb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline2Test.java @@ -0,0 +1,171 @@ +/** + * 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.usecases; + +import org.apache.activemq.broker.jmx.DurableSubscriptionViewMBean; +import org.apache.activemq.broker.jmx.TopicViewMBean; +import org.apache.activemq.util.Wait; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.*; + + +@RunWith(value = Parameterized.class) +public class DurableSubscriptionOffline2Test extends DurableSubscriptionOfflineTestBase { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionOffline2Test.class); + + @Parameterized.Parameters(name = "{0}") + public static Collection getTestParameters() { + Boolean[] f = {Boolean.FALSE}; + Boolean[] t = {Boolean.TRUE}; + List booleanChoices = new ArrayList(); + booleanChoices.add(f); + booleanChoices.add(t); + + return booleanChoices; + } + + public DurableSubscriptionOffline2Test(Boolean keepDurableSubsActive) { + this.keepDurableSubsActive = keepDurableSubsActive.booleanValue(); + + LOG.info(">>>> running {} with keepDurableSubsActive: {}", testName.getMethodName(), this.keepDurableSubsActive); + } + + + @Test(timeout = 60 * 1000) + public void testJMXCountersWithOfflineSubs() throws Exception { + // create durable subscription 1 + Connection con = createConnection("cliId1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", null, true); + session.close(); + con.close(); + + // restart broker + broker.stop(); + createBroker(false /*deleteAllMessages*/); + + // send messages + con = createConnection(); + 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(); + producer.send(topic, message); + } + session.close(); + con.close(); + + // consume some messages + con = createConnection("cliId1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + + for (int i=0; i getTestParameters() { + String osName = System.getProperty("os.name"); + LOG.debug("Running on [" + osName + "]"); + + PersistenceAdapterChoice[] kahaDb = {PersistenceAdapterChoice.KahaDB}; + PersistenceAdapterChoice[] jdbc = {PersistenceAdapterChoice.JDBC}; + List choices = new ArrayList(); + choices.add(kahaDb); + choices.add(jdbc); + if (!osName.equalsIgnoreCase("AIX") && !osName.equalsIgnoreCase("SunOS")) { + PersistenceAdapterChoice[] levelDb = {PersistenceAdapterChoice.LevelDB}; + choices.add(levelDb); + } + + return choices; + } + + public DurableSubscriptionOffline3Test(PersistenceAdapterChoice persistenceAdapterChoice) { + this.defaultPersistenceAdapter = persistenceAdapterChoice; + + LOG.info(">>>> running {} with persistenceAdapterChoice: {}", testName.getMethodName(), this.defaultPersistenceAdapter); + } + + @Test(timeout = 60 * 1000) + public void testInterleavedOfflineSubscriptionCanConsume() throws Exception { + // create durable subscription 1 + Connection con = createConnection("cliId1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + 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(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + + // 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(); + consumer2.setMessageListener(listener2); + + assertEquals(0, listener2.count); + session2.close(); + con2.close(); + + // send some more + for (int i = 0; i < 10; i++) { + sent++; + Message message = session.createMessage(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + con2 = createConnection("cliId2"); + session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer2 = session2.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + listener2 = new DurableSubscriptionOfflineTestListener("cliId2"); + consumer2.setMessageListener(listener2); + // test online subs + Thread.sleep(3 * 1000); + + assertEquals(10, listener2.count); + + // consume all messages + con = createConnection("cliId1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener("cliId1"); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals("offline consumer got all", sent, listener.count); + } + + private static String filter = "$a='A1' AND (($b=true AND $c=true) OR ($d='D1' OR $d='D2'))"; + @Test(timeout = 60 * 1000) + public void testMixOfOnLineAndOfflineSubsGetAllMatched() throws Exception { + // create offline subs 1 + Connection con = createConnection("offCli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", filter, true); + session.close(); + con.close(); + + // create offline subs 2 + con = createConnection("offCli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", filter, true); + session.close(); + con.close(); + + // create online subs + Connection con2 = createConnection("onlineCli1"); + Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer2 = session2.createDurableSubscriber(topic, "SubsId", filter, true); + DurableSubscriptionOfflineTestListener listener2 = new DurableSubscriptionOfflineTestListener(); + consumer2.setMessageListener(listener2); + + // create non-durable consumer + Connection con4 = createConnection("nondurableCli"); + Session session4 = con4.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer4 = session4.createConsumer(topic, filter, true); + DurableSubscriptionOfflineTestListener listener4 = new DurableSubscriptionOfflineTestListener(); + consumer4.setMessageListener(listener4); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + boolean hasRelevant = false; + int filtered = 0; + for (int i = 0; i < 100; i++) { + int postf = (int) (Math.random() * 9) + 1; + String d = "D" + postf; + + if ("D1".equals(d) || "D2".equals(d)) { + hasRelevant = true; + filtered++; + } + + Message message = session.createMessage(); + message.setStringProperty("$a", "A1"); + message.setStringProperty("$d", d); + producer.send(topic, message); + } + + Message message = session.createMessage(); + message.setStringProperty("$a", "A1"); + message.setBooleanProperty("$b", true); + message.setBooleanProperty("$c", hasRelevant); + producer.send(topic, message); + + if (hasRelevant) + filtered++; + + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + Thread.sleep(3 * 1000); + + // test non-durable consumer + session4.close(); + con4.close(); + assertEquals(filtered, listener4.count); // succeeded! + + // test online subs + session2.close(); + con2.close(); + assertEquals(filtered, listener2.count); // succeeded! + + // test offline 1 + con = createConnection("offCli1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); + DurableSubscriptionOfflineTestListener listener = new FilterCheckListener(); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + session.close(); + con.close(); + + assertEquals(filtered, listener.count); + + // test offline 2 + Connection con3 = createConnection("offCli2"); + Session session3 = con3.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer3 = session3.createDurableSubscriber(topic, "SubsId", filter, true); + DurableSubscriptionOfflineTestListener listener3 = new FilterCheckListener(); + consumer3.setMessageListener(listener3); + + Thread.sleep(3 * 1000); + session3.close(); + con3.close(); + + assertEquals(filtered, listener3.count); + assertTrue("no unexpected exceptions: " + exceptions, exceptions.isEmpty()); + } + + @Test(timeout = 60 * 1000) + public void testOfflineSubscriptionWithSelectorAfterRestart() throws Exception { + + if (PersistenceAdapterChoice.LevelDB == defaultPersistenceAdapter) { + // https://issues.apache.org/jira/browse/AMQ-4296 + return; + } + + // create offline subs 1 + Connection con = createConnection("offCli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // create offline subs 2 + con = createConnection("offCli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + int filtered = 0; + for (int i = 0; i < 10; i++) { + boolean filter = (int) (Math.random() * 2) >= 1; + if (filter) + filtered++; + + Message message = session.createMessage(); + message.setStringProperty("filter", filter ? "true" : "false"); + producer.send(topic, message); + } + + LOG.info("sent: " + filtered); + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + // restart broker + Thread.sleep(3 * 1000); + broker.stop(); + createBroker(false /*deleteAllMessages*/); + + // send more messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(null); + + for (int i = 0; i < 10; i++) { + boolean filter = (int) (Math.random() * 2) >= 1; + if (filter) + filtered++; + + Message message = session.createMessage(); + message.setStringProperty("filter", filter ? "true" : "false"); + producer.send(topic, message); + } + + LOG.info("after restart, total sent with filter='true': " + filtered); + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + // test offline subs + con = createConnection("offCli1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener("1>"); + consumer.setMessageListener(listener); + + Connection con3 = createConnection("offCli2"); + Session session3 = con3.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer3 = session3.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener3 = new DurableSubscriptionOfflineTestListener(); + consumer3.setMessageListener(listener3); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + session3.close(); + con3.close(); + + assertEquals(filtered, listener.count); + assertEquals(filtered, listener3.count); + } + + @Test(timeout = 60 * 1000) + public void testOfflineSubscriptionAfterRestart() throws Exception { + // create offline subs 1 + Connection con = createConnection("offCli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, false); + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + + // send messages + MessageProducer producer = session.createProducer(null); + + int sent = 0; + for (int i = 0; i < 10; i++) { + sent++; + Message message = session.createMessage(); + message.setStringProperty("filter", "false"); + producer.send(topic, message); + } + + LOG.info("sent: " + sent); + Thread.sleep(5 * 1000); + session.close(); + con.close(); + + assertEquals(sent, listener.count); + + // restart broker + Thread.sleep(3 * 1000); + broker.stop(); + createBroker(false /*deleteAllMessages*/); + + // send more messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(null); + + for (int i = 0; i < 10; i++) { + sent++; + Message message = session.createMessage(); + message.setStringProperty("filter", "false"); + producer.send(topic, message); + } + + LOG.info("after restart, sent: " + sent); + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + // test offline subs + con = createConnection("offCli1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals(sent, listener.count); + } + + public class FilterCheckListener extends DurableSubscriptionOfflineTestListener { + + @Override + public void onMessage(Message message) { + count++; + + try { + Object b = message.getObjectProperty("$b"); + if (b != null) { + boolean c = message.getBooleanProperty("$c"); + assertTrue("", c); + } else { + String d = message.getStringProperty("$d"); + assertTrue("", "D1".equals(d) || "D2".equals(d)); + } + } + catch (JMSException e) { + e.printStackTrace(); + exceptions.add(e); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline4Test.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline4Test.java new file mode 100644 index 0000000000..09c50d0107 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOffline4Test.java @@ -0,0 +1,131 @@ +/** + * 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.usecases; + +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertTrue; + + +@RunWith(value = Parameterized.class) +public class DurableSubscriptionOffline4Test extends DurableSubscriptionOfflineTestBase { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionOffline4Test.class); + + @Parameterized.Parameters(name = "keepDurableSubsActive_{0}") + public static Collection getTestParameters() { + Boolean[] f = {Boolean.FALSE}; + Boolean[] t = {Boolean.TRUE}; + List booleanChoices = new ArrayList(); + booleanChoices.add(f); + booleanChoices.add(t); + + return booleanChoices; + } + + public DurableSubscriptionOffline4Test(Boolean keepDurableSubsActive) { + this.journalMaxFileLength = 64 * 1024; + this.keepDurableSubsActive = keepDurableSubsActive.booleanValue(); + + LOG.info(">>>> running {} with keepDurableSubsActive: {}, journalMaxFileLength", testName.getMethodName(), this.keepDurableSubsActive, journalMaxFileLength); + } + + + @Test(timeout = 60 * 1000) + // https://issues.apache.org/jira/browse/AMQ-3206 + public void testCleanupDeletedSubAfterRestart() throws Exception { + Connection con = createConnection("cli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", null, true); + session.close(); + con.close(); + + con = createConnection("cli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", null, true); + session.close(); + con.close(); + + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + final int toSend = 500; + final String payload = new byte[40*1024].toString(); + int sent = 0; + for (int i = sent; i < toSend; i++) { + Message message = session.createTextMessage(payload); + message.setStringProperty("filter", "false"); + message.setIntProperty("ID", i); + producer.send(topic, message); + sent++; + } + con.close(); + LOG.info("sent: " + sent); + + // kill off cli1 + con = createConnection("cli1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe("SubsId"); + + destroyBroker(); + createBroker(false); + + con = createConnection("cli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + final DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + assertTrue("got all sent", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("Want: " + toSend + ", current: " + listener.count); + return listener.count == toSend; + } + })); + session.close(); + con.close(); + + destroyBroker(); + createBroker(false); + final KahaDBPersistenceAdapter pa = (KahaDBPersistenceAdapter) broker.getPersistenceAdapter(); + assertTrue("Should have less than three journal files left but was: " + + pa.getStore().getJournal().getFileMap().size(), Wait.waitFor(new Wait.Condition() { + + @Override + public boolean isSatisified() throws Exception { + return pa.getStore().getJournal().getFileMap().size() <= 3; + } + })); + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOfflineTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOfflineTest.java new file mode 100644 index 0000000000..a1ce526de8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOfflineTest.java @@ -0,0 +1,878 @@ +/** + * 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.usecases; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.MessageId; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.store.kahadb.disk.page.PageFile; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import java.util.HashSet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; + +public class DurableSubscriptionOfflineTest extends DurableSubscriptionOfflineTestBase { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionOfflineTest.class); + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); + connectionFactory.setWatchTopicAdvisories(false); + return connectionFactory; + } + + @Test(timeout = 60 * 1000) + public void testConsumeAllMatchedMessages() throws Exception { + // create durable subscription + Connection con = createConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + 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(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + + session.close(); + con.close(); + + // consume messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals(sent, listener.count); + } + + + @Test(timeout = 60 * 1000) + public void testTwoOfflineSubscriptionCanConsume() throws Exception { + // create durable subscription 1 + Connection con = createConnection("cliId1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + 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(); + consumer2.setMessageListener(listener2); + + // send messages + con = createConnection(); + 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(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + // test online subs + Thread.sleep(3 * 1000); + session2.close(); + con2.close(); + + assertEquals(sent, listener2.count); + + // 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(); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals("offline consumer got all", sent, listener.count); + } + + @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'))"; + // create durable subscription 1 + Connection con = createConnection("cliId1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + for (int i = 0; i < 10; i++) { + Message message = session.createMessage(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + + Connection con2 = createConnection("cliId1"); + Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + session2.unsubscribe("SubsId"); + session2.close(); + con2.close(); + + // see if retroactive can consumer any + 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(); + consumer.setMessageListener(listener); + session.close(); + con.close(); + assertEquals(0, listener.count); + } + + @Test(timeout = 60 * 1000) + public void testRemovedDurableSubDeletesFromIndex() throws Exception { + + if (! (broker.getPersistenceAdapter() instanceof KahaDBPersistenceAdapter)) { + return; + } + + final int numMessages = 2750; + + KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter)broker.getPersistenceAdapter(); + PageFile pageFile = kahaDBPersistenceAdapter.getStore().getPageFile(); + LOG.info("PageCount " + pageFile.getPageCount() + " f:" + pageFile.getFreePageCount() + ", fileSize:" + pageFile.getFile().length()); + + long lastDiff = 0; + for (int repeats=0; repeats<2; repeats++) { + + LOG.info("Iteration: "+ repeats + " Count:" + pageFile.getPageCount() + " f:" + pageFile.getFreePageCount()); + + Connection con = createConnection("cliId1" + "-" + repeats); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + for (int i = 0; i < numMessages; i++) { + 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); + session2.unsubscribe("SubsId"); + session2.close(); + con2.close(); + + LOG.info("PageCount " + pageFile.getPageCount() + " f:" + pageFile.getFreePageCount() + " diff: " + (pageFile.getPageCount() - pageFile.getFreePageCount()) + " fileSize:" + pageFile.getFile().length()); + + if (lastDiff != 0) { + assertEquals("Only use X pages per iteration: " + repeats, lastDiff, pageFile.getPageCount() - pageFile.getFreePageCount()); + } + lastDiff = pageFile.getPageCount() - pageFile.getFreePageCount(); + } + } + + @Test(timeout = 60 * 1000) + public void testInterleavedOfflineSubscriptionCanConsumeAfterUnsub() throws Exception { + // create offline subs 1 + Connection con = createConnection("offCli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // create offline subs 2 + con = createConnection("offCli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", null, true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + int sent = 0; + for (int i = 0; i < 10; i++) { + boolean filter = (int) (Math.random() * 2) >= 1; + + sent++; + + Message message = session.createMessage(); + message.setStringProperty("filter", filter ? "true" : "false"); + producer.send(topic, message); + } + + Thread.sleep(1 * 1000); + + Connection con2 = createConnection("offCli1"); + Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + session2.unsubscribe("SubsId"); + session2.close(); + con2.close(); + + // 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"); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals("offline consumer got all", sent, listener.count); + } + + @Test(timeout = 60 * 1000) + public void testNoDuplicateOnConcurrentSendTranCommitAndActivate() throws Exception { + final int messageCount = 1000; + Connection con = null; + Session session = null; + final int numConsumers = 10; + for (int i = 0; i <= numConsumers; i++) { + con = createConnection("cli" + i); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", null, true); + session.close(); + con.close(); + } + + class CheckForDupsClient implements Runnable { + HashSet ids = new HashSet(); + final int id; + + public CheckForDupsClient(int id) { + this.id = id; + } + + @Override + public void run() { + try { + Connection con = createConnection("cli" + id); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + for (int j=0;j<2;j++) { + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + for (int i = 0; i < messageCount/2; i++) { + Message message = consumer.receive(4000); + assertNotNull(message); + 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); + if (message != null) { + long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); + assertTrue("ID=" + id + " not a duplicate: " + producerSequenceId, ids.add(producerSequenceId)); + } + assertNull(message); + + + session.close(); + con.close(); + } catch (Throwable e) { + e.printStackTrace(); + exceptions.add(e); + } + } + } + + final String payLoad = new String(new byte[1000]); + con = createConnection(); + final Session sendSession = con.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = sendSession.createProducer(topic); + for (int i = 0; i < messageCount; i++) { + producer.send(sendSession.createTextMessage(payLoad)); + } + + 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); + } + } + }); + for (int i = 0; i < numConsumers; i++) { + executorService.execute(new CheckForDupsClient(i)); + } + + executorService.shutdown(); + executorService.awaitTermination(5, TimeUnit.MINUTES); + con.close(); + + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + } + + + @Test(timeout = 2 * 60 * 1000) + public void testOrderOnActivateDeactivate() throws Exception { + for (int i=0;i<10;i++) { + LOG.info("Iteration: " + i); + doTestOrderOnActivateDeactivate(); + broker.stop(); + broker.waitUntilStopped(); + createBroker(true /*deleteAllMessages*/); + } + } + + + public void doTestOrderOnActivateDeactivate() throws Exception { + final int messageCount = 1000; + Connection con = null; + Session session = null; + final int numConsumers = 4; + for (int i = 0; i <= numConsumers; i++) { + con = createConnection("cli" + i); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", null, true); + session.close(); + con.close(); + } + + final String url = "failover:(tcp://localhost:" + + (broker.getTransportConnectors().get(1).getConnectUri()).getPort() + + "?wireFormat.maxInactivityDuration=0)?" + + "jms.watchTopicAdvisories=false&" + + "jms.alwaysSyncSend=true&jms.dispatchAsync=true&" + + "jms.sendAcksAsync=true&" + + "initialReconnectDelay=100&maxReconnectDelay=30000&" + + "useExponentialBackOff=true"; + final ActiveMQConnectionFactory clientFactory = new ActiveMQConnectionFactory(url); + + class CheckOrderClient implements Runnable { + final int id; + int runCount = 0; + + public CheckOrderClient(int id) { + this.id = id; + } + + @Override + public void run() { + try { + synchronized (this) { + 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); + int nextId = 0; + + ++runCount; + int i=0; + for (; i < messageCount/2; i++) { + Message message = consumer.receiveNoWait(); + if (message == null) { + break; + } + long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); + assertEquals(id + " expected order: runCount: " + runCount + " id: " + message.getJMSMessageID(), ++nextId, producerSequenceId); + } + LOG.info(con.getClientID() + " peeked " + i); + session.close(); + con.close(); + } + } catch (Throwable e) { + e.printStackTrace(); + exceptions.add(e); + } + } + } + + Runnable producer = new Runnable() { + final String payLoad = new String(new byte[600]); + + @Override + public void run() { + try { + Connection con = createConnection(); + final Session sendSession = con.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = sendSession.createProducer(topic); + for (int i = 0; i < messageCount; i++) { + producer.send(sendSession.createTextMessage(payLoad)); + } + LOG.info("About to commit: " + messageCount); + sendSession.commit(); + LOG.info("committed: " + messageCount); + con.close(); + } catch (Exception e) { + e.printStackTrace(); + exceptions.add(e); + } + } + }; + + ExecutorService executorService = Executors.newCachedThreadPool(); + + // concurrent commit and activate + for (int i = 0; i < numConsumers; i++) { + final CheckOrderClient client = new CheckOrderClient(i); + for (int j=0; j<100; j++) { + executorService.execute(client); + } + } + executorService.execute(producer); + + executorService.shutdown(); + executorService.awaitTermination(5, TimeUnit.MINUTES); + con.close(); + + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + } + + @Test(timeout = 60 * 1000) + public void testUnmatchedSubUnsubscribeDeletesAll() throws Exception { + // create offline subs 1 + Connection con = createConnection("offCli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + 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; + if (filter) + filtered++; + + Message message = session.createMessage(); + message.setStringProperty("filter", filter ? "true" : "false"); + producer.send(topic, message); + } + + LOG.info("sent: " + filtered); + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + // test offline subs + con = createConnection("offCli1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe("SubsId"); + session.close(); + con.close(); + + con = createConnection("offCli1"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener); + + Thread.sleep(3 * 1000); + + session.close(); + con.close(); + + assertEquals(0, listener.count); + } + + @Test(timeout = 60 * 1000) + public void testAllConsumed() throws Exception { + final String filter = "filter = 'true'"; + Connection con = createConnection("cli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", filter, true); + session.close(); + con.close(); + + con = createConnection("cli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", filter, true); + session.close(); + con.close(); + + // send messages + con = createConnection(); + 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(); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + sent++; + } + + LOG.info("sent: " + sent); + Thread.sleep(1 * 1000); + 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); + session.close(); + con.close(); + + assertEquals(sent, listener.count); + + LOG.info("cli2 pull 2"); + con = createConnection("cli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); + assertNotNull("got message", consumer.receive(2000)); + assertNotNull("got message", consumer.receive(2000)); + session.close(); + con.close(); + + // send messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(null); + + sent = 0; + for (int i = 0; i < 2; i++) { + Message message = session.createMessage(); + message.setStringProperty("filter", i==1 ? "true" : "false"); + producer.send(topic, message); + sent++; + } + LOG.info("sent: " + sent); + Thread.sleep(1 * 1000); + session.close(); + con.close(); + + LOG.info("cli1 again, should get 1 new ones"); + 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); + session.close(); + con.close(); + + assertEquals(1, listener.count); + } + + // https://issues.apache.org/jira/browse/AMQ-3190 + @Test(timeout = 60 * 1000) + public void testNoMissOnMatchingSubAfterRestart() throws Exception { + + final String filter = "filter = 'true'"; + Connection con = createConnection("cli1"); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", filter, true); + session.close(); + con.close(); + + // send unmatched messages + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(null); + + int sent = 0; + // message for cli1 to keep it interested + Message message = session.createMessage(); + message.setStringProperty("filter", "true"); + message.setIntProperty("ID", 0); + producer.send(topic, message); + sent++; + + for (int i = sent; i < 10; i++) { + message = session.createMessage(); + message.setStringProperty("filter", "false"); + message.setIntProperty("ID", i); + producer.send(topic, message); + sent++; + } + con.close(); + LOG.info("sent: " + sent); + + // new sub at id 10 + con = createConnection("cli2"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId", filter, true); + session.close(); + con.close(); + + destroyBroker(); + createBroker(false); + + con = createConnection(); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(null); + + for (int i = sent; i < 30; i++) { + message = session.createMessage(); + message.setStringProperty("filter", "true"); + message.setIntProperty("ID", i); + producer.send(topic, message); + sent++; + } + con.close(); + LOG.info("sent: " + sent); + + // 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); + assertEquals("is message 10", 10, m.getIntProperty("ID")); + + session.close(); + con.close(); + + // 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")); + + session.close(); + con.close(); + } + + +// // https://issues.apache.org/jira/browse/AMQ-3768 +// public void testPageReuse() throws Exception { +// Connection con = null; +// Session session = null; +// +// final int numConsumers = 115; +// for (int i=0; i<=numConsumers;i++) { +// con = createConnection("cli" + i); +// session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); +// session.createDurableSubscriber(topic, "SubsId", null, true); +// session.close(); +// con.close(); +// } +// +// // populate ack locations +// con = createConnection(); +// session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); +// MessageProducer producer = session.createProducer(null); +// Message message = session.createTextMessage(new byte[10].toString()); +// producer.send(topic, message); +// con.close(); +// +// // we have a split, remove all but the last so that +// // the head pageid changes in the acklocations listindex +// for (int i=0; i<=numConsumers -1; i++) { +// con = createConnection("cli" + i); +// session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); +// session.unsubscribe("SubsId"); +// session.close(); +// con.close(); +// } +// +// destroyBroker(); +// createBroker(false); +// +// // create a bunch more subs to reuse the freed page and get us in a knot +// for (int i=1; i<=numConsumers;i++) { +// con = createConnection("cli" + i); +// session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); +// session.createDurableSubscriber(topic, "SubsId", filter, true); +// session.close(); +// con.close(); +// } +// } +// +// public void testRedeliveryFlag() throws Exception { +// +// Connection con; +// Session session; +// final int numClients = 2; +// for (int i=0; i exceptions = new ArrayList(); + protected ActiveMQConnectionFactory connectionFactory; + protected boolean isTopic = true; + public PersistenceAdapterChoice defaultPersistenceAdapter = PersistenceAdapterChoice.KahaDB; + + @Rule + public TestName testName = new TestName(); + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); + connectionFactory.setWatchTopicAdvisories(false); + return connectionFactory; + } + + protected Connection createConnection() throws Exception { + return createConnection("cliName"); + } + + protected Connection createConnection(String name) throws Exception { + ConnectionFactory connectionFactory1 = createConnectionFactory(); + Connection connection = connectionFactory1.createConnection(); + connection.setClientID(name); + connection.start(); + return connection; + } + + public ActiveMQConnectionFactory getConnectionFactory() throws Exception { + if (connectionFactory == null) { + connectionFactory = createConnectionFactory(); + assertTrue("Should have created a connection factory!", connectionFactory != null); + } + return connectionFactory; + } + + @Before + public void setUp() throws Exception { + exceptions.clear(); + topic = (ActiveMQTopic) createDestination(); + createBroker(); + } + + @After + public void tearDown() throws Exception { + destroyBroker(); + } + + protected void createBroker() throws Exception { + createBroker(true); + } + + protected void createBroker(boolean deleteAllMessages) throws Exception { + String currentTestName = getName(true); + broker = BrokerFactory.createBroker("broker:(vm://" + currentTestName +")"); + broker.setBrokerName(currentTestName); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + broker.getManagementContext().setCreateConnector(false); + broker.setAdvisorySupport(false); + broker.setKeepDurableSubsActive(keepDurableSubsActive); + broker.addConnector("tcp://0.0.0.0:0"); + + if (usePrioritySupport) { + PolicyEntry policy = new PolicyEntry(); + policy.setPrioritizedMessages(true); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(policy); + broker.setDestinationPolicy(policyMap); + } + + setDefaultPersistenceAdapter(broker); + if (broker.getPersistenceAdapter() instanceof JDBCPersistenceAdapter) { + // ensure it kicks in during tests + ((JDBCPersistenceAdapter)broker.getPersistenceAdapter()).setCleanupPeriod(2*1000); + } else if (broker.getPersistenceAdapter() instanceof KahaDBPersistenceAdapter) { + // have lots of journal files + ((KahaDBPersistenceAdapter)broker.getPersistenceAdapter()).setJournalMaxFileLength(journalMaxFileLength); + } + broker.start(); + broker.waitUntilStarted(); + } + + protected void destroyBroker() throws Exception { + if (broker != null) + broker.stop(); + } + + protected Destination createDestination(String subject) { + if (isTopic) { + return new ActiveMQTopic(subject); + } else { + return new ActiveMQQueue(subject); + } + } + + protected Destination createDestination() { + return createDestination(getDestinationString()); + } + + /** + * Returns the name of the destination used in this test case + */ + protected String getDestinationString() { + return getClass().getName() + "." + getName(true); + } + + + public String getName() { + return getName(false); + } + + protected String getName(boolean original) { + String currentTestName = testName.getMethodName(); + currentTestName = currentTestName.replace("[",""); + currentTestName = currentTestName.replace("]",""); + return currentTestName; + } + + public PersistenceAdapter setDefaultPersistenceAdapter(BrokerService broker) throws IOException { + return setPersistenceAdapter(broker, defaultPersistenceAdapter); + } + + public PersistenceAdapter setPersistenceAdapter(BrokerService broker, PersistenceAdapterChoice choice) throws IOException { + PersistenceAdapter adapter = null; + switch (choice) { + case JDBC: + LOG.debug(">>>> setPersistenceAdapter to JDBC "); + adapter = new JDBCPersistenceAdapter(); + break; + case KahaDB: + LOG.debug(">>>> setPersistenceAdapter to KahaDB "); + adapter = new KahaDBPersistenceAdapter(); + break; + case LevelDB: + LOG.debug(">>>> setPersistenceAdapter to LevelDB "); + adapter = new LevelDBPersistenceAdapter(); + break; + case MEM: + LOG.debug(">>>> setPersistenceAdapter to MEM "); + adapter = new MemoryPersistenceAdapter(); + break; + } + broker.setPersistenceAdapter(adapter); + return adapter; + } +} + +class DurableSubscriptionOfflineTestListener implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionOfflineTestListener.class); + int count = 0; + String id = null; + + DurableSubscriptionOfflineTestListener() {} + + DurableSubscriptionOfflineTestListener(String id) { + this.id = id; + } + @Override + public void onMessage(javax.jms.Message message) { + count++; + if (id != null) { + try { + LOG.info(id + ", " + message.getJMSMessageID()); + } catch (Exception ignored) {} + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionReactivationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionReactivationTest.java new file mode 100644 index 0000000000..7bd50a8355 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionReactivationTest.java @@ -0,0 +1,95 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import junit.framework.Test; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; + +public class DurableSubscriptionReactivationTest extends EmbeddedBrokerTestSupport { + + public boolean keepDurableSubsActive; + + public void initCombosForTestReactivateKeepaliveSubscription() { + addCombinationValues("keepDurableSubsActive", new Object[] { new Boolean(true), new Boolean(false) }); + } + + public void testReactivateKeepaliveSubscription() throws Exception { + + Connection connection = createConnection(); + connection.setClientID("cliID"); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber subscriber = session.createDurableSubscriber((Topic) createDestination(), "subName"); + subscriber.close(); + connection.close(); + + connection = createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(createDestination()); + producer.send(session.createMessage()); + connection.close(); + + connection = createConnection(); + connection.setClientID("cliID"); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + subscriber = session.createDurableSubscriber((Topic) createDestination(), "subName"); + Message message = subscriber.receive(1 * 1000); + subscriber.close(); + connection.close(); + + assertNotNull("Message not received.", message); + } + + protected void setUp() throws Exception { + useTopic = true; + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = super.createBroker(); + answer.setKeepDurableSubsActive(keepDurableSubsActive); + answer.setPersistenceAdapter(new JDBCPersistenceAdapter()); + answer.setDeleteAllMessagesOnStartup(true); + return answer; + } + + protected boolean isPersistent() { + return true; + } + + public static Test suite() { + return suite(DurableSubscriptionReactivationTest.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionRemoveOfflineTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionRemoveOfflineTest.java new file mode 100644 index 0000000000..1e2c08c0f6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionRemoveOfflineTest.java @@ -0,0 +1,118 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import junit.framework.Test; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DurableSubscriptionRemoveOfflineTest extends EmbeddedBrokerTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(DurableSubscriptionRemoveOfflineTest.class); + + protected void setUp() throws Exception { + useTopic = true; + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService answer = super.createBroker(); + answer.setOfflineDurableSubscriberTaskSchedule(3 * 1000); + answer.setOfflineDurableSubscriberTimeout(5 * 1000); + answer.setDeleteAllMessagesOnStartup(true); + return answer; + } + + protected BrokerService restartBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + broker = null; + + broker = super.createBroker(); + broker.setOfflineDurableSubscriberTaskSchedule(3 * 1000); + broker.setOfflineDurableSubscriberTimeout(5 * 1000); + + broker.start(); + broker.waitUntilStarted(); + + return broker; + } + + public void testRemove() throws Exception { + Connection connection = createConnection(); + connection.setClientID("cliID"); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber subscriber = session.createDurableSubscriber((Topic) createDestination(), "subName"); + subscriber.close(); + connection.close(); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker.getAdminView().getInactiveDurableTopicSubscribers().length == 0; + } + }, 15000)); + } + + public void testRemoveAfterRestart() throws Exception { + Connection connection = createConnection(); + connection.setClientID("cliID"); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber subscriber = session.createDurableSubscriber((Topic) createDestination(), "subName"); + subscriber.close(); + connection.close(); + + LOG.info("Broker restarting, wait for inactive cleanup afterwards."); + + restartBroker(); + + LOG.info("Broker restarted, wait for inactive cleanup now."); + + assertTrue(broker.getAdminView().getInactiveDurableTopicSubscribers().length == 1); + + assertTrue(Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return broker.getAdminView().getInactiveDurableTopicSubscribers().length == 0; + } + }, 20000)); + } + + protected boolean isPersistent() { + return true; + } + + public static Test suite() { + return suite(DurableSubscriptionRemoveOfflineTest.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionSelectorTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionSelectorTest.java new file mode 100644 index 0000000000..317866d2cd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionSelectorTest.java @@ -0,0 +1,177 @@ +/** + * 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.usecases; + +import java.lang.management.ManagementFactory; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TopicSubscriber; +import javax.management.MBeanServer; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; + +public class DurableSubscriptionSelectorTest extends org.apache.activemq.TestSupport { + + MBeanServer mbs; + BrokerService broker = null; + ActiveMQTopic topic; + + ActiveMQConnection consumerConnection = null, producerConnection = null; + Session producerSession; + MessageProducer producer; + + private int received = 0; + + public static Test suite() { + return suite(DurableSubscriptionSelectorTest.class); + } + + public void initCombosForTestSubscription() throws Exception { + this.addCombinationValues("defaultPersistenceAdapter", PersistenceAdapterChoice.values()); + } + + public void testSubscription() throws Exception { + openConsumer(); + for (int i = 0; i < 4000; i++) { + sendMessage(false); + } + Thread.sleep(1000); + + assertEquals("Invalid message received.", 0, received); + + closeProducer(); + closeConsumer(); + stopBroker(); + + startBroker(false); + openConsumer(); + + sendMessage(true); + + Wait.waitFor(new Wait.Condition() { @Override + public boolean isSatisified() { return received >= 1;} }, 10000); + + assertEquals("Message is not received.", 1, received); + + sendMessage(true); + Thread.sleep(100); + + assertEquals("Message is not received.", 2, received); + } + + private void openConsumer() throws Exception { + consumerConnection = (ActiveMQConnection) createConnection(); + consumerConnection.setClientID("cliID"); + consumerConnection.start(); + Session session = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber subscriber = session.createDurableSubscriber(topic, "subName", "filter=true", false); + + subscriber.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received++; + } + }); + } + + private void closeConsumer() throws JMSException { + if (consumerConnection != null) + consumerConnection.close(); + consumerConnection = null; + } + + private void sendMessage(boolean filter) throws Exception { + if (producerConnection == null) { + producerConnection = (ActiveMQConnection) createConnection(); + producerConnection.start(); + producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = producerSession.createProducer(topic); + } + + Message message = producerSession.createMessage(); + message.setBooleanProperty("filter", filter); + producer.send(message); + } + + private void closeProducer() throws JMSException { + if (producerConnection != null) + producerConnection.close(); + producerConnection = null; + } + + private void startBroker(boolean deleteMessages) throws Exception { + broker = new BrokerService(); + broker.setBrokerName("test-broker"); + + if (deleteMessages) { + broker.setDeleteAllMessagesOnStartup(true); + } + setDefaultPersistenceAdapter(broker); + + /* use maxPageSize policy in place of always pulling from the broker in maxRows chunks + if (broker.getPersistenceAdapter() instanceof JDBCPersistenceAdapter) { + ((JDBCPersistenceAdapter)broker.getPersistenceAdapter()).setMaxRows(5000); + }*/ + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setMaxPageSize(5000); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + + broker.start(); + } + + private void stopBroker() throws Exception { + if (broker != null) + broker.stop(); + broker = null; + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://test-broker?jms.watchTopicAdvisories=false&waitForStart=5000&create=false"); + } + + @Override + protected void setUp() throws Exception { + setAutoFail(true); + super.setUp(); + + startBroker(true); + topic = (ActiveMQTopic) createDestination(); + mbs = ManagementFactory.getPlatformMBeanServer(); + } + + @Override + protected void tearDown() throws Exception { + stopBroker(); + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionTestSupport.java new file mode 100644 index 0000000000..b610f8c530 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionTestSupport.java @@ -0,0 +1,534 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; + +/** + * + */ +public abstract class DurableSubscriptionTestSupport extends TestSupport { + + private Connection connection; + private Session session; + private TopicSubscriber consumer; + private MessageProducer producer; + private BrokerService broker; + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://durable-broker"); + } + + @Override + protected Connection createConnection() throws Exception { + Connection rc = super.createConnection(); + rc.setClientID(getName()); + return rc; + } + + @Override + protected void setUp() throws Exception { + createBroker(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + protected void restartBroker() throws Exception { + destroyBroker(); + createRestartedBroker(); // retain stored messages + } + + private void createBroker() throws Exception { + broker = new BrokerService(); + broker.setBrokerName("durable-broker"); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistenceAdapter(createPersistenceAdapter()); + broker.setPersistent(true); + broker.start(); + broker.waitUntilStarted(); + + connection = createConnection(); + } + + private void createRestartedBroker() throws Exception { + broker = new BrokerService(); + broker.setBrokerName("durable-broker"); + broker.setDeleteAllMessagesOnStartup(false); + broker.setPersistenceAdapter(createPersistenceAdapter()); + broker.setPersistent(true); + broker.start(); + broker.waitUntilStarted(); + + connection = createConnection(); + } + + private void destroyBroker() throws Exception { + if (connection != null) { + connection.close(); + } + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + protected abstract PersistenceAdapter createPersistenceAdapter() throws Exception; + + public void testMessageExpire() throws Exception { + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TestTopic"); + consumer = session.createDurableSubscriber(topic, "sub1"); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.setTimeToLive(1000); + connection.start(); + + // Make sure it works when the durable sub is active. + producer.send(session.createTextMessage("Msg:1")); + assertTextMessageEquals("Msg:1", consumer.receive(1000)); + + consumer.close(); + + producer.send(session.createTextMessage("Msg:2")); + producer.send(session.createTextMessage("Msg:3")); + + consumer = session.createDurableSubscriber(topic, "sub1"); + + // Try to get the message. + assertTextMessageEquals("Msg:2", consumer.receive(1000)); + Thread.sleep(1000); + assertNull(consumer.receive(1000)); + } + + public void testUnsubscribeSubscription() throws Exception { + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TestTopic"); + consumer = session.createDurableSubscriber(topic, "sub1"); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + // Make sure it works when the durable sub is active. + producer.send(session.createTextMessage("Msg:1")); + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + + // Deactivate the sub. + consumer.close(); + // Send a new message. + producer.send(session.createTextMessage("Msg:2")); + session.unsubscribe("sub1"); + + // Reopen the connection. + connection.close(); + connection = createConnection(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(topic); + connection.start(); + + // Activate the sub. + consumer = session.createDurableSubscriber(topic, "sub1"); + producer.send(session.createTextMessage("Msg:3")); + + // Try to get the message. + assertTextMessageEquals("Msg:3", consumer.receive(5000)); + } + + public void testInactiveDurableSubscriptionTwoConnections() throws Exception { + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TestTopic"); + consumer = session.createDurableSubscriber(topic, "sub1"); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + // Make sure it works when the durable sub is active. + producer.send(session.createTextMessage("Msg:1")); + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + + // Deactivate the sub. + consumer.close(); + + // Send a new message. + producer.send(session.createTextMessage("Msg:2")); + + // Reopen the connection. + connection.close(); + connection = createConnection(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + connection.start(); + + // Activate the sub. + consumer = session.createDurableSubscriber(topic, "sub1"); + + // Try to get the message. + assertTextMessageEquals("Msg:2", consumer.receive(5000)); + } + + public void testInactiveDurableSubscriptionBrokerRestart() throws Exception { + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TestTopic"); + consumer = session.createDurableSubscriber(topic, "sub1"); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + // Make sure it works when the durable sub is active. + producer.send(session.createTextMessage("Msg:1")); + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + + // Deactivate the sub. + consumer.close(); + + // Send a new message. + producer.send(session.createTextMessage("Msg:2")); + + // Reopen the connection. + restartBroker(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + connection.start(); + + // Activate the sub. + consumer = session.createDurableSubscriber(topic, "sub1"); + + // Try to get the message. + assertTextMessageEquals("Msg:2", consumer.receive(5000)); + assertNull(consumer.receive(5000)); + } + + public void testDurableSubscriptionBrokerRestart() throws Exception { + + // Create the durable sub. + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + + // Ensure that consumer will receive messages sent before it was created + Topic topic = session.createTopic("TestTopic?consumer.retroactive=true"); + consumer = session.createDurableSubscriber(topic, "sub1"); + + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.send(session.createTextMessage("Msg:1")); + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + + // Make sure cleanup kicks in + Thread.sleep(1000); + + // Restart the broker. + restartBroker(); + } + + public void testDurableSubscriptionPersistsPastBrokerRestart() throws Exception { + + // Create the durable sub. + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + + // Ensure that consumer will receive messages sent before it was created + Topic topic = session.createTopic("TestTopic?consumer.retroactive=true"); + consumer = session.createDurableSubscriber(topic, "sub1"); + + // Restart the broker. + restartBroker(); + + // Reconnection + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + // Make sure it works when the durable sub is active. + producer.send(session.createTextMessage("Msg:1")); + + // Activate the sub. + consumer = session.createDurableSubscriber(topic, "sub1"); + + // Send a new message. + producer.send(session.createTextMessage("Msg:2")); + + // Try to get the message. + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + assertTextMessageEquals("Msg:2", consumer.receive(5000)); + + assertNull(consumer.receive(5000)); + } + + public void testDurableSubscriptionRetroactive() throws Exception { + + // Create the durable sub. + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + + Topic topic = session.createTopic("TestTopic?consumer.retroactive=true"); + consumer = session.createDurableSubscriber(topic, "sub1"); + connection.close(); + + // Produce + connection = createConnection(); + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.send(session.createTextMessage("Msg:1")); + + restartBroker(); + + // connect second durable to pick up retroactive message + connection.start(); + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + consumer = session.createDurableSubscriber(topic, "sub2"); + + // Try to get the message. + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + assertNull(consumer.receive(2000)); + } + + public void testDurableSubscriptionRollbackRedeliver() throws Exception { + + // Create the durable sub. + connection.start(); + + session = connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED); + Topic topic = session.createTopic("TestTopic"); + consumer = session.createDurableSubscriber(topic, "sub1"); + + Session producerSession = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + producer = producerSession.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + producer.send(session.createTextMessage("Msg:1")); + + // receive and rollback + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + session.rollback(); + consumer.close(); + session.close(); + + session = connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED); + + // Ensure that consumer will receive messages sent and rolled back + consumer = session.createDurableSubscriber(topic, "sub1"); + + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + session.commit(); + + assertNull(consumer.receive(5000)); + } + + public void xtestInactiveDurableSubscriptionOneConnection() throws Exception { + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TestTopic"); + consumer = session.createDurableSubscriber(topic, "sub1"); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + // Make sure it works when the durable sub is active. + producer.send(session.createTextMessage("Msg:1")); + assertTextMessageEquals("Msg:1", consumer.receive(5000)); + + // Deactivate the sub. + consumer.close(); + + // Send a new message. + producer.send(session.createTextMessage("Msg:2")); + + // Activate the sub. + consumer = session.createDurableSubscriber(topic, "sub1"); + + // Try to get the message. + assertTextMessageEquals("Msg:2", consumer.receive(5000)); + } + + public void testSelectorChange() throws Exception { + session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("TestTopic"); + consumer = session.createDurableSubscriber(topic, "sub1", "color='red'", false); + producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + connection.start(); + + // Make sure it works when the durable sub is active. + TextMessage msg = session.createTextMessage(); + msg.setText("Msg:1"); + msg.setStringProperty("color", "blue"); + producer.send(msg); + msg.setText("Msg:2"); + msg.setStringProperty("color", "red"); + producer.send(msg); + + assertTextMessageEquals("Msg:2", consumer.receive(5000)); + + // Change the subscription + consumer.close(); + consumer = session.createDurableSubscriber(topic, "sub1", "color='blue'", false); + + // Send a new message. + msg.setText("Msg:3"); + msg.setStringProperty("color", "red"); + producer.send(msg); + msg.setText("Msg:4"); + msg.setStringProperty("color", "blue"); + producer.send(msg); + + // Try to get the message. + assertTextMessageEquals("Msg:4", consumer.receive(5000)); + } + + public void testDurableSubWorksInNewSession() throws JMSException { + + // Create the consumer. + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1"); + // Drain any messages that may allready be in the sub + while (consumer.receive(1000) != null) { + } + + // See if the durable sub works in a new session. + session.close(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Send a Message that should be added to the durable sub. + MessageProducer producer = createProducer(session, topic); + producer.send(session.createTextMessage("Message 1")); + + // Activate the durable sub now. And receive the message. + consumer = session.createDurableSubscriber(topic, "sub1"); + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertEquals("Message 1", ((TextMessage) msg).getText()); + } + + public void testDurableSubWorksInNewConnection() throws Exception { + + // Create the consumer. + connection.start(); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1"); + // Drain any messages that may allready be in the sub + while (consumer.receive(1000) != null) { + } + + // See if the durable sub works in a new connection. + // The embeded broker shutsdown when his connections are closed. + // So we open the new connection before the old one is closed. + connection.close(); + connection = createConnection(); + connection.start(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Send a Message that should be added to the durable sub. + MessageProducer producer = createProducer(session, topic); + producer.send(session.createTextMessage("Message 1")); + + // Activate the durable sub now. And receive the message. + consumer = session.createDurableSubscriber(topic, "sub1"); + Message msg = consumer.receive(1000); + assertNotNull(msg); + assertEquals("Message 1", ((TextMessage) msg).getText()); + } + + public void testIndividualAckWithDurableSubs() throws Exception { + // Create the consumer. + connection.start(); + + Session session = connection.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE); + Topic topic = session.createTopic("topic-" + getName()); + MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1"); + // Drain any messages that may allready be in the sub + while (consumer.receive(1000) != null) { + } + consumer.close(); + + MessageProducer producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + producer.send(session.createTextMessage("Message 1")); + producer.send(session.createTextMessage("Message 2")); + producer.send(session.createTextMessage("Message 3")); + producer.close(); + + connection.close(); + connection = createConnection(); + connection.start(); + + session = connection.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE); + consumer = session.createDurableSubscriber(topic, "sub1"); + + Message message = null; + for (int i = 0; i < 3; ++i) { + message = consumer.receive(5000); + assertNotNull(message); + assertEquals("Message " + (i + 1), ((TextMessage) message).getText()); + } + + message.acknowledge(); + + connection.close(); + connection = createConnection(); + connection.start(); + + session = connection.createSession(false, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE); + consumer = session.createDurableSubscriber(topic, "sub1"); + + for (int i = 0; i < 2; ++i) { + message = consumer.receive(5000); + assertNotNull(message); + assertEquals("Message " + (i + 1), ((TextMessage) message).getText()); + } + } + + private MessageProducer createProducer(Session session, Destination queue) throws JMSException { + MessageProducer producer = session.createProducer(queue); + producer.setDeliveryMode(getDeliveryMode()); + return producer; + } + + protected int getDeliveryMode() { + return DeliveryMode.PERSISTENT; + } + + private void assertTextMessageEquals(String string, Message message) throws JMSException { + assertNotNull("Message was null", message); + assertTrue("Message is not a TextMessage", message instanceof TextMessage); + assertEquals(string, ((TextMessage) message).getText()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionUnsubscribeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionUnsubscribeTest.java new file mode 100644 index 0000000000..d0ecfdef90 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionUnsubscribeTest.java @@ -0,0 +1,340 @@ +/** + * 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.usecases; + +import java.io.File; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.*; +import javax.management.InstanceNotFoundException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.jmx.DurableSubscriptionViewMBean; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.DurableTopicSubscription; +import org.apache.activemq.broker.region.Subscription; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.RemoveSubscriptionInfo; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; + +public class DurableSubscriptionUnsubscribeTest extends TestSupport { + + BrokerService broker = null; + Connection connection = null; + ActiveMQTopic topic; + + public void testJMXSubscriptionUnsubscribe() throws Exception { + doJMXUnsubscribe(false); + } + + public void testJMXSubscriptionUnsubscribeWithRestart() throws Exception { + doJMXUnsubscribe(true); + } + + public void testConnectionSubscriptionUnsubscribe() throws Exception { + doConnectionUnsubscribe(false); + } + + public void testConnectionSubscriptionUnsubscribeWithRestart() throws Exception { + doConnectionUnsubscribe(true); + } + + public void testDirectSubscriptionUnsubscribe() throws Exception { + doDirectUnsubscribe(false); + } + + public void testDirectubscriptionUnsubscribeWithRestart() throws Exception { + doDirectUnsubscribe(true); + } + + public void doJMXUnsubscribe(boolean restart) throws Exception { + createSubscriptions(); + createAdvisorySubscription(); + + Thread.sleep(1000); + assertCount(100, 0); + + if (restart) { + restartBroker(); + createAdvisorySubscription(); + assertCount(100, 0); + } + + 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); + sub.destroy(); + + if (i % 20 == 0) { + Thread.sleep(1000); + assertCount(100 - i - 1, 0); + } + } + + Thread.sleep(1000); + assertCount(0, 0); + + if (restart) { + restartBroker(); + createAdvisorySubscription(); + assertCount(0, 0); + } + } + + public void doConnectionUnsubscribe(boolean restart) throws Exception { + createSubscriptions(); + createAdvisorySubscription(); + + Thread.sleep(1000); + assertCount(100, 0); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId1"); + + Thread.sleep(1000); + assertCount(100, 1); + + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session2.createDurableSubscriber(topic, "SubsId2"); + + Thread.sleep(1000); + assertCount(100, 2); + + session.close(); + + Thread.sleep(1000); + assertCount(100, 1); + + session2.close(); + + Thread.sleep(1000); + assertCount(100, 0); + + if (restart) { + restartBroker(); + createAdvisorySubscription(); + assertCount(100, 0); + } + + for (int i = 0; i < 100; i++) { + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.unsubscribe("SubsId" + i); + session.close(); + + if (i % 20 == 0) { + Thread.sleep(1000); + assertCount(100 - i - 1, 0); + } + } + + Thread.sleep(1000); + assertCount(0, 0); + + if (restart) { + restartBroker(); + createAdvisorySubscription(); + assertCount(0, 0); + } + } + + public void doDirectUnsubscribe(boolean restart) throws Exception { + createSubscriptions(); + createAdvisorySubscription(); + + Thread.sleep(1000); + assertCount(100, 0); + + if (restart) { + restartBroker(); + createAdvisorySubscription(); + assertCount(100, 0); + } + + for (int i = 0; i < 100; i++) { + RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + info.setClientId(getName()); + info.setSubscriptionName("SubsId" + i); + 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); + } + } + + assertCount(0, 0); + + if (restart) { + restartBroker(); + createAdvisorySubscription(); + assertCount(0, 0); + } + } + + private void createSubscriptions() throws Exception { + for (int i = 0; i < 100; i++) { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId" + i); + session.close(); + } + } + + 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(); + } + } + }); + } + + private void assertCount(int all, int active) throws Exception { + int inactive = all - active; + + // broker check + Destination destination = broker.getDestination(topic); + List subs = destination.getConsumers(); + int cActive = 0, cInactive = 0; + for (Subscription sub: subs) { + if (sub instanceof DurableTopicSubscription) { + DurableTopicSubscription durable = (DurableTopicSubscription) sub; + if (durable.isActive()) + cActive++; + else + cInactive++; + } + } + assertEquals(active, cActive); + assertEquals(inactive, cInactive); + + // admin view + ObjectName[] subscriptions = broker.getAdminView().getDurableTopicSubscribers(); + assertEquals(active, subscriptions.length); + subscriptions = broker.getAdminView().getInactiveDurableTopicSubscribers(); + assertEquals(inactive, subscriptions.length); + + // check the strange false MBean + if (all == 0) + assertEquals(0, countMBean()); + + // check if we got all advisories + assertEquals(100, all + advisories.get()); + } + + 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); + try { + broker.getManagementContext().getObjectInstance(sub); + count++; + } + catch (InstanceNotFoundException ignore) { + // this should happen + } + } + return count; + } + + private void startBroker(boolean deleteMessages) throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://" + getName() + ")"); + broker.setUseJmx(true); + broker.getManagementContext().setCreateConnector(false); + broker.setBrokerName(getName()); + + broker.setPersistent(true); + KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); + persistenceAdapter.setDirectory(new File("activemq-data/" + getName())); + broker.setPersistenceAdapter(persistenceAdapter); + if (deleteMessages) { + broker.setDeleteAllMessagesOnStartup(true); + } + + + broker.setKeepDurableSubsActive(true); + + broker.start(); + broker.waitUntilStarted(); + + connection = createConnection(); + } + + private void stopBroker() throws Exception { + if (connection != null) + connection.close(); + connection = null; + + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + broker = null; + } + + private void restartBroker() throws Exception { + stopBroker(); + startBroker(false); + } + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://" + getName() + "?waitForStart=5000&create=false"); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + topic = (ActiveMQTopic) createDestination(); + startBroker(true); + } + + @Override + protected void tearDown() throws Exception { + stopBroker(); + super.tearDown(); + } + + @Override + protected Connection createConnection() throws Exception { + Connection rc = super.createConnection(); + rc.setClientID(getName()); + rc.start(); + return rc; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableUnsubscribeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableUnsubscribeTest.java new file mode 100644 index 0000000000..b42ce52d31 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/DurableUnsubscribeTest.java @@ -0,0 +1,119 @@ +/** + * 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.usecases; + +import java.lang.management.ManagementFactory; + +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQTopic; + +public class DurableUnsubscribeTest extends org.apache.activemq.TestSupport { + + private BrokerService broker; + private Connection connection; + private ActiveMQTopic topic; + + public void testUnsubscribe() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId"); + session.close(); + + Destination d = broker.getDestination(topic); + assertEquals("Subscription is missing.", 1, d.getConsumers().size()); + + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(topic); + for (int i = 0; i < 1000; i++) { + producer.send(session.createTextMessage("text")); + } + + Thread.sleep(1000); + + session.unsubscribe("SubsId"); + session.close(); + + assertEquals("Subscription exists.", 0, d.getConsumers().size()); + } + + public void testDestroy() throws Exception { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId2"); + session.close(); + + connection.close(); + connection = null; + Thread.sleep(1000); + + Destination d = broker.getDestination(topic); + assertEquals("Subscription is missing.", 1, d.getConsumers().size()); + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName[] subNames = broker.getAdminView().getInactiveDurableTopicSubscribers(); + mbs.invoke(subNames[0], "destroy", new Object[0], new String[0]); + + assertEquals("Subscription exists.", 0, d.getConsumers().size()); + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://" + getName()); + } + + protected Connection createConnection() throws Exception { + Connection rc = super.createConnection(); + rc.setClientID(getName()); + return rc; + } + + protected void setUp() throws Exception { + topic = (ActiveMQTopic) createDestination(); + createBroker(); + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + private void createBroker() throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://localhost)"); + //broker.setPersistent(false); + broker.setUseJmx(true); + broker.setBrokerName(getName()); + broker.deleteAllMessages(); + broker.start(); + + connection = createConnection(); + } + + private void destroyBroker() throws Exception { + if (connection != null) + connection.close(); + if (broker != null) + broker.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExceptionListenerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExceptionListenerTest.java new file mode 100644 index 0000000000..e426b126b2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExceptionListenerTest.java @@ -0,0 +1,118 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.ArrayList; +import java.util.LinkedList; +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.JMSSecurityException; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ConnectionFailedException; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.security.SimpleAuthenticationPlugin; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @author Oliver Belikan + */ +public class ExceptionListenerTest implements ExceptionListener { + private static final Logger LOG = LoggerFactory.getLogger(ExceptionListenerTest.class); + BrokerService brokerService; + URI brokerUri; + LinkedList exceptionsViaListener = new LinkedList(); + + @Before + public void startBroker() throws Exception { + brokerService = new BrokerService(); + brokerService.setAdvisorySupport(false); + brokerService.setUseJmx(false); + brokerService.setPersistent(false); + brokerService.setPlugins(new BrokerPlugin[]{new SimpleAuthenticationPlugin(new ArrayList())}); + brokerUri = brokerService.addConnector("tcp://0.0.0.0:0").getConnectUri(); + brokerService.start(); + } + + @After + public void stopBroker() throws Exception { + exceptionsViaListener.clear(); + if (brokerService != null) { + brokerService.stop(); + } + } + + @Test + public void fireOnSecurityException() throws Exception { + doFireOnSecurityException(new ActiveMQConnectionFactory(brokerUri)); + } + + @Test + public void fireOnSecurityExceptionFailover() throws Exception { + doFireOnSecurityException(new ActiveMQConnectionFactory("failover://" + brokerUri)); + } + + public void doFireOnSecurityException(ActiveMQConnectionFactory factory) throws Exception { + factory.setWatchTopicAdvisories(false); + Connection connection = factory.createConnection(); + connection.setExceptionListener(this); + + try { + connection.start(); + fail("Expect securityException"); + } catch (JMSSecurityException expected) { + expected.printStackTrace(); + assertTrue("nested security exception: " + expected, expected.getCause() instanceof SecurityException); + } + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return !exceptionsViaListener.isEmpty(); + } + }); + Throwable expected = exceptionsViaListener.getFirst(); + assertNotNull(expected); + assertNotNull(expected.getCause()); + + assertTrue("expected exception: " + expected, expected.getCause().getCause() instanceof SecurityException); + + try { + connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + fail("Expect error b/c connection is auto closed on security exception above"); + } catch (ConnectionFailedException e) { + } + } + + public void onException(JMSException e) { + LOG.info("onException:" + e, new Throwable("FromHere")); + exceptionsViaListener.add(e); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExpiredMessagesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExpiredMessagesTest.java new file mode 100644 index 0000000000..02055991fc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExpiredMessagesTest.java @@ -0,0 +1,321 @@ +/** + * 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.usecases; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationStatistics; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.store.memory.MemoryPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; + +import java.io.File; +import java.util.concurrent.atomic.AtomicLong; + +import static org.apache.activemq.TestSupport.getDestination; +import static org.apache.activemq.TestSupport.getDestinationStatistics; + +public class ExpiredMessagesTest extends CombinationTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(ExpiredMessagesTest.class); + + BrokerService broker; + Connection connection; + Session session; + MessageProducer producer; + MessageConsumer consumer; + public ActiveMQDestination destination = new ActiveMQQueue("test"); + public ActiveMQDestination dlqDestination = new ActiveMQQueue("ActiveMQ.DLQ"); + public boolean useTextMessage = true; + public boolean useVMCursor = true; + protected String brokerUri; + + public static Test suite() { + return suite(ExpiredMessagesTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + protected void setUp() throws Exception { + final boolean deleteAllMessages = true; + broker = createBroker(deleteAllMessages, 100); + brokerUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + @Override + protected void tearDown() throws Exception { + connection.stop(); + broker.stop(); + broker.waitUntilStopped(); + } + + public void testExpiredMessages() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUri); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(destination); + producer.setTimeToLive(100); + consumer = session.createConsumer(destination); + connection.start(); + final AtomicLong received = new AtomicLong(); + + Thread consumerThread = new Thread("Consumer Thread") { + @Override + public void run() { + long start = System.currentTimeMillis(); + try { + long end = System.currentTimeMillis(); + while (end - start < 3000) { + if (consumer.receive(1000) != null) { + received.incrementAndGet(); + } + Thread.sleep(100); + end = System.currentTimeMillis(); + } + consumer.close(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + consumerThread.start(); + + final int numMessagesToSend = 10000; + Thread producingThread = new Thread("Producing Thread") { + @Override + public void run() { + try { + int i = 0; + while (i++ < numMessagesToSend) { + producer.send(session.createTextMessage("test")); + } + producer.close(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + producingThread.start(); + + consumerThread.join(); + producingThread.join(); + session.close(); + + final DestinationStatistics view = getDestinationStatistics(broker, destination); + + // wait for all to inflight to expire + assertTrue("all inflight messages expired ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return view.getInflight().getCount() == 0; + } + })); + assertEquals("Wrong inFlightCount: ", 0, view.getInflight().getCount()); + + LOG.info("Stats: received: " + received.get() + ", enqueues: " + view.getEnqueues().getCount() + ", dequeues: " + view.getDequeues().getCount() + + ", dispatched: " + view.getDispatched().getCount() + ", inflight: " + view.getInflight().getCount() + ", expiries: " + view.getExpired().getCount()); + + // wait for all sent to get delivered and expire + assertTrue("all sent messages expired ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + long oldEnqueues = view.getEnqueues().getCount(); + Thread.sleep(200); + LOG.info("Stats: received: " + received.get() + ", size= " + view.getMessages().getCount() + ", enqueues: " + view.getDequeues().getCount() + ", dequeues: " + view.getDequeues().getCount() + + ", dispatched: " + view.getDispatched().getCount() + ", inflight: " + view.getInflight().getCount() + ", expiries: " + view.getExpired().getCount()); + return oldEnqueues == view.getEnqueues().getCount(); + } + }, 60*1000)); + + + LOG.info("Stats: received: " + received.get() + ", size= " + view.getMessages().getCount() + ", enqueues: " + view.getEnqueues().getCount() + ", dequeues: " + view.getDequeues().getCount() + + ", dispatched: " + view.getDispatched().getCount() + ", inflight: " + view.getInflight().getCount() + ", expiries: " + view.getExpired().getCount()); + + assertTrue("got at least what did not expire", received.get() >= view.getDequeues().getCount() - view.getExpired().getCount()); + + assertTrue("all messages expired - queue size gone to zero " + view.getMessages().getCount(), Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("Stats: received: " + received.get() + ", size= " + view.getMessages().getCount() + ", enqueues: " + view.getEnqueues().getCount() + ", dequeues: " + view.getDequeues().getCount() + + ", dispatched: " + view.getDispatched().getCount() + ", inflight: " + view.getInflight().getCount() + ", expiries: " + view.getExpired().getCount()); + return view.getMessages().getCount() == 0; + } + })); + + final long expiredBeforeEnqueue = numMessagesToSend - view.getEnqueues().getCount(); + final long totalExpiredCount = view.getExpired().getCount() + expiredBeforeEnqueue; + + final DestinationStatistics dlqView = getDestinationStatistics(broker, dlqDestination); + LOG.info("DLQ stats: size= " + dlqView.getMessages().getCount() + ", enqueues: " + dlqView.getDequeues().getCount() + ", dequeues: " + dlqView.getDequeues().getCount() + + ", dispatched: " + dlqView.getDispatched().getCount() + ", inflight: " + dlqView.getInflight().getCount() + ", expiries: " + dlqView.getExpired().getCount()); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return totalExpiredCount == dlqView.getMessages().getCount(); + } + }); + assertEquals("dlq contains all expired", totalExpiredCount, dlqView.getMessages().getCount()); + + // memory check + assertEquals("memory usage is back to duck egg", 0, getDestination(broker, destination).getMemoryUsage().getPercentUsage()); + assertTrue("memory usage is increased ", 0 < getDestination(broker, dlqDestination).getMemoryUsage().getUsage()); + + // verify DLQ + MessageConsumer dlqConsumer = createDlqConsumer(connection); + final DLQListener dlqListener = new DLQListener(); + dlqConsumer.setMessageListener(dlqListener); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return totalExpiredCount == dlqListener.count; + } + }, 60 * 1000); + + assertEquals("dlq returned all expired", dlqListener.count, totalExpiredCount); + } + + class DLQListener implements MessageListener { + + int count = 0; + + @Override + public void onMessage(Message message) { + count++; + } + + }; + + private MessageConsumer createDlqConsumer(Connection connection) throws Exception { + return connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(dlqDestination); + } + + public void initCombosForTestRecoverExpiredMessages() { + addCombinationValues("useVMCursor", new Object[] {Boolean.TRUE, Boolean.FALSE}); + } + + public void testRecoverExpiredMessages() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + "failover://"+brokerUri); + connection = factory.createConnection(); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(destination); + producer.setTimeToLive(2000); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + Thread producingThread = new Thread("Producing Thread") { + @Override + public void run() { + try { + int i = 0; + while (i++ < 1000) { + Message message = useTextMessage ? session + .createTextMessage("test") : session + .createObjectMessage("test"); + producer.send(message); + } + producer.close(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + producingThread.start(); + producingThread.join(); + + DestinationStatistics view = getDestinationStatistics(broker, destination); + LOG.info("Stats: size: " + view.getMessages().getCount() + ", enqueues: " + + view.getEnqueues().getCount() + ", dequeues: " + + view.getDequeues().getCount() + ", dispatched: " + + view.getDispatched().getCount() + ", inflight: " + + view.getInflight().getCount() + ", expiries: " + + view.getExpired().getCount()); + + LOG.info("stopping broker"); + broker.stop(); + broker.waitUntilStopped(); + + Thread.sleep(5000); + + LOG.info("recovering broker"); + final boolean deleteAllMessages = false; + broker = createBroker(deleteAllMessages, 5000); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + DestinationStatistics view = getDestinationStatistics(broker, destination); + LOG.info("Stats: size: " + view.getMessages().getCount() + ", enqueues: " + + view.getEnqueues().getCount() + ", dequeues: " + + view.getDequeues().getCount() + ", dispatched: " + + view.getDispatched().getCount() + ", inflight: " + + view.getInflight().getCount() + ", expiries: " + + view.getExpired().getCount()); + + return view.getMessages().getCount() == 0; + } + }); + + view = getDestinationStatistics(broker, destination); + assertEquals("Expect empty queue, QueueSize: ", 0, view.getMessages().getCount()); + assertEquals("all dequeues were expired", view.getDequeues().getCount(), view.getExpired().getCount()); + } + + private BrokerService createBroker(boolean deleteAllMessages, long expireMessagesPeriod) throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("localhost"); + broker.setDestinations(new ActiveMQDestination[]{destination}); + broker.setPersistenceAdapter(new MemoryPersistenceAdapter()); + + PolicyEntry defaultPolicy = new PolicyEntry(); + if (useVMCursor) { + defaultPolicy.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + } + defaultPolicy.setExpireMessagesPeriod(expireMessagesPeriod); + defaultPolicy.setMaxExpirePageSize(1200); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(defaultPolicy); + broker.setDestinationPolicy(policyMap); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + broker.addConnector("tcp://localhost:0"); + broker.start(); + broker.waitUntilStarted(); + return broker; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExpiredMessagesWithNoConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExpiredMessagesWithNoConsumerTest.java new file mode 100644 index 0000000000..e2ad7f602a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ExpiredMessagesWithNoConsumerTest.java @@ -0,0 +1,614 @@ +/** + * 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.usecases; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; +import javax.management.ObjectName; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.DestinationViewMBean; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExpiredMessagesWithNoConsumerTest extends CombinationTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(ExpiredMessagesWithNoConsumerTest.class); + + private final ActiveMQDestination destination = new ActiveMQQueue("test"); + + private boolean optimizedDispatch = true; + private PendingQueueMessageStoragePolicy pendingQueuePolicy; + + private BrokerService broker; + private String connectionUri; + private Connection connection; + private Session session; + private MessageProducer producer; + + public static Test suite() { + return suite(ExpiredMessagesWithNoConsumerTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + protected void createBrokerWithMemoryLimit() throws Exception { + createBrokerWithMemoryLimit(800); + } + + protected void createBrokerWithMemoryLimit(int expireMessagesPeriod) throws Exception { + doCreateBroker(true, expireMessagesPeriod); + } + + protected void createBroker() throws Exception { + doCreateBroker(false, 800); + } + + private void doCreateBroker(boolean memoryLimit, int expireMessagesPeriod) throws Exception { + broker = new BrokerService(); + broker.setBrokerName("localhost"); + broker.setUseJmx(true); + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector("tcp://localhost:0"); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setOptimizedDispatch(optimizedDispatch); + defaultEntry.setExpireMessagesPeriod(expireMessagesPeriod); + defaultEntry.setMaxExpirePageSize(800); + + defaultEntry.setPendingQueuePolicy(pendingQueuePolicy); + + if (memoryLimit) { + // so memory is not consumed by DLQ turn if off + defaultEntry.setDeadLetterStrategy(null); + defaultEntry.setMemoryLimit(200 * 1000); + } + + policyMap.setDefaultEntry(defaultEntry); + + broker.setDestinationPolicy(policyMap); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + } + + public void testExpiredNonPersistentMessagesWithNoConsumer() throws Exception { + + createBrokerWithMemoryLimit(2000); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(destination); + producer.setTimeToLive(1000); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + connection.start(); + final long sendCount = 2000; + + final Thread producingThread = new Thread("Producing Thread") { + @Override + public void run() { + try { + int i = 0; + long tStamp = System.currentTimeMillis(); + while (i++ < sendCount) { + producer.send(session.createTextMessage("test")); + if (i%100 == 0) { + LOG.info("sent: " + i + " @ " + ((System.currentTimeMillis() - tStamp) / 100) + "m/ms"); + tStamp = System.currentTimeMillis() ; + } + + if (135 == i) { + // allow pending messages to expire, before usage limit kicks in to flush them + TimeUnit.SECONDS.sleep(5); + } + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + producingThread.start(); + + assertTrue("producer failed to complete within allocated time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + producingThread.join(TimeUnit.SECONDS.toMillis(3000)); + return !producingThread.isAlive(); + } + })); + + TimeUnit.SECONDS.sleep(5); + + final DestinationViewMBean view = createView(destination); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + try { + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + return view.getDequeueCount() != 0 + && view.getDequeueCount() == view.getExpiredCount() + && view.getDequeueCount() == view.getEnqueueCount() + && view.getQueueSize() == 0; + } catch (Exception ignored) { + LOG.info(ignored.toString()); + } + return false; + } + }, Wait.MAX_WAIT_MILLIS * 10); + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + assertEquals("memory usage doesn't go to duck egg", 0, view.getMemoryPercentUsage()); + assertEquals("0 queue", 0, view.getQueueSize()); + } + + + public void initCombosForTestExpiredMessagesWithNoConsumer() { + addCombinationValues("optimizedDispatch", new Object[] {Boolean.TRUE, Boolean.FALSE}); + addCombinationValues("pendingQueuePolicy", new Object[] {null, new VMPendingQueueMessageStoragePolicy(), new FilePendingQueueMessageStoragePolicy()}); + } + + public void testExpiredMessagesWithNoConsumer() throws Exception { + + createBrokerWithMemoryLimit(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + connection = factory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(destination); + producer.setTimeToLive(1000); + connection.start(); + final long sendCount = 2000; + + final Thread producingThread = new Thread("Producing Thread") { + @Override + public void run() { + try { + int i = 0; + long tStamp = System.currentTimeMillis(); + while (i++ < sendCount) { + producer.send(session.createTextMessage("test")); + if (i%100 == 0) { + LOG.info("sent: " + i + " @ " + ((System.currentTimeMillis() - tStamp) / 100) + "m/ms"); + tStamp = System.currentTimeMillis() ; + } + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + producingThread.start(); + + assertTrue("producer failed to complete within allocated time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + producingThread.join(TimeUnit.SECONDS.toMillis(3000)); + return !producingThread.isAlive(); + } + })); + + final DestinationViewMBean view = createView(destination); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + return sendCount == view.getExpiredCount(); + } + }, Wait.MAX_WAIT_MILLIS * 10); + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + assertEquals("Not all sent messages have expired", sendCount, view.getExpiredCount()); + assertEquals("memory usage doesn't go to duck egg", 0, view.getMemoryPercentUsage()); + } + + // first ack delivered after expiry + public void testExpiredMessagesWithVerySlowConsumer() throws Exception { + createBroker(); + final long queuePrefetch = 5; + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + connectionUri + "?jms.prefetchPolicy.queuePrefetch=" + queuePrefetch); + connection = factory.createConnection(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + producer = session.createProducer(destination); + final int ttl = 4000; + producer.setTimeToLive(ttl); + + final long sendCount = 10; + final CountDownLatch receivedOneCondition = new CountDownLatch(1); + final CountDownLatch waitCondition = new CountDownLatch(1); + + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + try { + LOG.info("Got my message: " + message); + receivedOneCondition.countDown(); + waitCondition.await(6, TimeUnit.MINUTES); + LOG.info("acking message: " + message); + message.acknowledge(); + } catch (Exception e) { + e.printStackTrace(); + fail(e.toString()); + } + } + }); + + connection.start(); + + final Thread producingThread = new Thread("Producing Thread") { + @Override + public void run() { + try { + int i = 0; + long tStamp = System.currentTimeMillis(); + while (i++ < sendCount) { + producer.send(session.createTextMessage("test")); + if (i%100 == 0) { + LOG.info("sent: " + i + " @ " + ((System.currentTimeMillis() - tStamp) / 100) + "m/ms"); + tStamp = System.currentTimeMillis() ; + } + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + producingThread.start(); + assertTrue("got one message", receivedOneCondition.await(20, TimeUnit.SECONDS)); + + assertTrue("producer failed to complete within allocated time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + producingThread.join(1000); + return !producingThread.isAlive(); + } + }, Wait.MAX_WAIT_MILLIS * 10)); + + final DestinationViewMBean view = createView(destination); + + assertTrue("all dispatched up to default prefetch ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return queuePrefetch == view.getDispatchCount(); + } + })); + assertTrue("all non inflight have expired ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + return view.getExpiredCount() > 0 && (view.getEnqueueCount() - view.getInFlightCount()) == view.getExpiredCount(); + } + })); + + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + // let the ack happen + waitCondition.countDown(); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == view.getInFlightCount(); + } + }); + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + assertEquals("inflight reduced to duck", + 0, view.getInFlightCount()); + assertEquals("size didn't get back to 0 ", 0, view.getQueueSize()); + assertEquals("dequeues didn't match sent/expired ", sendCount, view.getDequeueCount()); + + consumer.close(); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == view.getInFlightCount(); + } + }); + assertEquals("inflight goes to zero on close", 0, view.getInFlightCount()); + + LOG.info("done: " + getName()); + } + + public void testExpiredMessagesWithVerySlowConsumerCanContinue() throws Exception { + createBroker(); + final long queuePrefetch = 600; + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + connectionUri + "?jms.prefetchPolicy.queuePrefetch=" + queuePrefetch); + connection = factory.createConnection(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + producer = session.createProducer(destination); + final int ttl = 4000; + producer.setTimeToLive(ttl); + + final long sendCount = 1500; + final CountDownLatch receivedOneCondition = new CountDownLatch(1); + final CountDownLatch waitCondition = new CountDownLatch(1); + final AtomicLong received = new AtomicLong(); + MessageConsumer consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message message) { + try { + if(LOG.isDebugEnabled()) { + LOG.debug("Got my message: " + message); + } + receivedOneCondition.countDown(); + received.incrementAndGet(); + waitCondition.await(5, TimeUnit.MINUTES); + if(LOG.isDebugEnabled()) { + LOG.debug("acking message: " + message); + } + message.acknowledge(); + } catch (Exception e) { + e.printStackTrace(); + fail(e.toString()); + } + } + }); + + connection.start(); + + final Thread producingThread = new Thread("Producing Thread") { + @Override + public void run() { + try { + int i = 0; + long tStamp = System.currentTimeMillis(); + while (i++ < sendCount) { + producer.send(session.createTextMessage("test")); + if (i%100 == 0) { + LOG.info("sent: " + i + " @ " + ((System.currentTimeMillis() - tStamp) / 100) + "m/ms"); + tStamp = System.currentTimeMillis() ; + } + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + } + }; + + producingThread.start(); + assertTrue("got one message", receivedOneCondition.await(20, TimeUnit.SECONDS)); + + assertTrue("producer failed to complete within allocated time", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + producingThread.join(1000); + return !producingThread.isAlive(); + } + }, Wait.MAX_WAIT_MILLIS * 10)); + + final DestinationViewMBean view = createView(destination); + + assertTrue("Not all dispatched up to default prefetch ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return queuePrefetch == view.getDispatchCount(); + } + })); + + assertTrue("all non inflight have expired ", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + return view.getExpiredCount() > 0 && (view.getEnqueueCount() - view.getInFlightCount()) == view.getExpiredCount(); + } + })); + + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + // let the ack happen + waitCondition.countDown(); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == view.getInFlightCount(); + } + }); + LOG.info("enqueue=" + view.getEnqueueCount() + ", dequeue=" + view.getDequeueCount() + + ", inflight=" + view.getInFlightCount() + ", expired= " + view.getExpiredCount() + + ", size= " + view.getQueueSize()); + + assertEquals("inflight didn't reduce to duck", + 0, view.getInFlightCount()); + assertEquals("size doesn't get back to 0 ", 0, view.getQueueSize()); + assertEquals("dequeues don't match sent/expired ", sendCount, view.getDequeueCount()); + + // produce some more + producer.setTimeToLive(0); + long tStamp = System.currentTimeMillis(); + for (int i=0; i= sendCount; + } + }); + + consumer.close(); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == view.getInFlightCount(); + } + }); + assertEquals("inflight did not go to zero on close", 0, view.getInFlightCount()); + + LOG.info("done: " + getName()); + } + + public void testExpireMessagesForDurableSubscriber() throws Exception { + createBroker(); + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri); + connection = factory.createConnection(); + connection.setClientID("myConnection"); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + connection.start(); + Topic destination = session.createTopic("test"); + producer = session.createProducer(destination); + final int ttl = 1000; + producer.setTimeToLive(ttl); + + final long sendCount = 10; + + TopicSubscriber sub = session.createDurableSubscriber(destination, "mySub"); + sub.close(); + + for (int i=0; i < sendCount; i++) { + producer.send(session.createTextMessage("test")); + } + + DestinationViewMBean view = createView((ActiveMQTopic)destination); + + LOG.info("messages sent"); + LOG.info("expired=" + view.getExpiredCount() + " " + view.getEnqueueCount()); + assertEquals(0, view.getExpiredCount()); + assertEquals(10, view.getEnqueueCount()); + + Thread.sleep(5000); + + LOG.info("expired=" + view.getExpiredCount() + " " + view.getEnqueueCount()); + assertEquals(10, view.getExpiredCount()); + assertEquals(10, view.getEnqueueCount()); + + final AtomicLong received = new AtomicLong(); + sub = session.createDurableSubscriber(destination, "mySub"); + sub.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received.incrementAndGet(); + } + }); + + LOG.info("Waiting for messages to arrive"); + + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return received.get() >= sendCount; + } + }, 1000); + + LOG.info("received=" + received.get()); + LOG.info("expired=" + view.getExpiredCount() + " " + view.getEnqueueCount()); + + assertEquals(0, received.get()); + assertEquals(10, view.getExpiredCount()); + assertEquals(10, view.getEnqueueCount()); + } + + protected DestinationViewMBean createView(ActiveMQDestination destination) throws Exception { + String domain = "org.apache.activemq"; + ObjectName name; + if (destination.isQueue()) { + name = new ObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=test"); + } else { + name = new ObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=test"); + } + + return (DestinationViewMBean) broker.getManagementContext().newProxyInstance(name, DestinationViewMBean.class, true); + } + + @Override + protected void tearDown() throws Exception { + connection.stop(); + broker.stop(); + broker.waitUntilStopped(); + } + + public boolean getOptimizedDispatch() { + return this.optimizedDispatch; + } + + public void setOptimizedDispatch(boolean option) { + this.optimizedDispatch = option; + } + + public PendingQueueMessageStoragePolicy getPendingQueuePolicy() { + return this.pendingQueuePolicy; + } + + public void setPendingQueuePolicy(PendingQueueMessageStoragePolicy policy) { + this.pendingQueuePolicy = policy; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JDBCDurableSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JDBCDurableSubscriptionTest.java new file mode 100644 index 0000000000..33afc85a9e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JDBCDurableSubscriptionTest.java @@ -0,0 +1,40 @@ +/** + * 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.usecases; + +import java.io.IOException; + +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.apache.derby.jdbc.EmbeddedDataSource; + +/** + * + */ +public class JDBCDurableSubscriptionTest extends DurableSubscriptionTestSupport { + + protected PersistenceAdapter createPersistenceAdapter() throws IOException { + JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + EmbeddedDataSource dataSource = new EmbeddedDataSource(); + dataSource.setDatabaseName("derbyDb"); + dataSource.setCreateDatabase("create"); + jdbc.setDataSource(dataSource); + jdbc.setCleanupPeriod(1000); // set up small cleanup period + return jdbc; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JMXRemoveQueueThenSendIgnoredTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JMXRemoveQueueThenSendIgnoredTest.java new file mode 100644 index 0000000000..7c301f535b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JMXRemoveQueueThenSendIgnoredTest.java @@ -0,0 +1,155 @@ +/** + * 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.usecases; + +import static org.junit.Assert.assertEquals; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JMXRemoveQueueThenSendIgnoredTest { + + private static final Logger LOG = LoggerFactory.getLogger(JMXRemoveQueueThenSendIgnoredTest.class); + private static final String domain = "org.apache.activemq"; + + private BrokerService brokerService; + private MessageProducer producer; + private QueueSession session; + private QueueConnection connection; + private Queue queue; + private int count = 1; + + @Before + public void setUp() throws Exception { + brokerService = new BrokerService(); + brokerService.setBrokerName("dev"); + brokerService.setPersistent(false); + brokerService.setUseJmx(true); + brokerService.addConnector("tcp://localhost:0"); + brokerService.start(); + + final String brokerUri = brokerService.getTransportConnectors().get(0).getPublishableConnectString(); + + ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(brokerUri); + connection = activeMQConnectionFactory.createQueueConnection(); + session = connection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE/*SESSION_TRANSACTED*/); + queue = session.createQueue("myqueue"); + producer = session.createProducer(queue); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + connection.start(); + } + + @Test + public void testRemoveQueueAndProduceAfterNewConsumerAdded() throws Exception { + MessageConsumer firstConsumer = registerConsumer(); + produceMessage(); + Message message = firstConsumer.receive(5000); + LOG.info("Received message " + message); + + assertEquals(1, numberOfMessages()); + firstConsumer.close(); + session.commit(); + Thread.sleep(1000); + + removeQueue(); + Thread.sleep(1000); + + MessageConsumer secondConsumer = registerConsumer(); + produceMessage(); + message = secondConsumer.receive(5000); + LOG.debug("Received message " + message); + + assertEquals(1, numberOfMessages()); + secondConsumer.close(); + } + + @Test + public void testRemoveQueueAndProduceBeforeNewConsumerAdded() throws Exception { + MessageConsumer firstConsumer = registerConsumer(); + produceMessage(); + Message message = firstConsumer.receive(5000); + LOG.info("Received message " + message); + + assertEquals(1, numberOfMessages()); + firstConsumer.close(); + session.commit(); + Thread.sleep(1000); + + removeQueue(); + Thread.sleep(1000); + + produceMessage(); + MessageConsumer secondConsumer = registerConsumer(); + message = secondConsumer.receive(5000); + LOG.debug("Received message " + message); + + assertEquals(1, numberOfMessages()); + secondConsumer.close(); + } + + private MessageConsumer registerConsumer() throws JMSException { + MessageConsumer consumer = session.createConsumer(queue); + return consumer; + } + + private int numberOfMessages() throws Exception { + ObjectName queueViewMBeanName = new ObjectName( + domain + ":destinationType=Queue,destinationName=myqueue,type=Broker,brokerName=dev"); + QueueViewMBean queue = (QueueViewMBean) + brokerService.getManagementContext().newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true); + long size = queue.getQueueSize(); + return (int)size; + } + + private void removeQueue() throws Exception { + LOG.debug("Removing Destination: myqueue"); + brokerService.getAdminView().removeQueue("myqueue"); + } + + private void produceMessage() throws JMSException { + TextMessage textMessage = session.createTextMessage(); + textMessage.setText("Sending message: " + count++); + LOG.debug("Sending message: " + textMessage); + producer.send(textMessage); + session.commit(); + } + + @After + public void tearDown() throws Exception { + connection.close(); + brokerService.stop(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JdbcDurableSubDupTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JdbcDurableSubDupTest.java new file mode 100644 index 0000000000..0cb2648bf2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JdbcDurableSubDupTest.java @@ -0,0 +1,297 @@ +/** + * 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.usecases; + +import static org.junit.Assert.assertTrue; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JdbcDurableSubDupTest { + + private static final Logger LOG = LoggerFactory.getLogger(JdbcDurableSubDupTest.class); + final int prefetchVal = 150; + String urlOptions = "jms.watchTopicAdvisories=false"; + String url = null; + String queueName = "topicTest?consumer.prefetchSize=" + prefetchVal; + String xmlMessage = ""; + + String selector = ""; + String clntVersion = "87"; + String clntId = "timsClntId345" + clntVersion; + String subscriptionName = "subscriptionName-y" + clntVersion; + SimpleDateFormat dtf = new SimpleDateFormat("HH:mm:ss"); + + final int TO_RECEIVE = 5000; + BrokerService broker = null; + Vector exceptions = new Vector(); + final int MAX_MESSAGES = 100000; + int[] dupChecker = new int[MAX_MESSAGES]; + + @Before + public void startBroker() throws Exception { + exceptions.clear(); + for (int i = 0; i < MAX_MESSAGES; i++) { + dupChecker[i] = 0; + } + broker = new BrokerService(); + broker.setAdvisorySupport(false); + broker.setPersistenceAdapter(new JDBCPersistenceAdapter()); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setMaxAuditDepth(3000); + policyEntry.setMaxPageSize(150); + policyEntry.setPrioritizedMessages(true); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(policyEntry); + broker.setDestinationPolicy(policyMap); + + broker.addConnector("tcp://localhost:0"); + broker.setDeleteAllMessagesOnStartup(true); + broker.start(); + broker.waitUntilStarted(); + url = broker.getTransportConnectors().get(0).getConnectUri().toString() + "?" + urlOptions; + } + + @After + public void stopBroker() throws Exception { + if (broker != null) { + broker.stop(); + } + } + + @Test + public void testNoDupsOnSlowConsumerReconnect() throws Exception { + JmsConsumerDup consumer = new JmsConsumerDup(); + consumer.done.set(true); + consumer.run(); + + consumer.done.set(false); + + LOG.info("serial production then consumption"); + JmsProvider provider = new JmsProvider(); + provider.run(); + + consumer.run(); + + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + + for (int i = 0; i < TO_RECEIVE; i++) { + assertTrue("got message " + i, dupChecker[i] == 1); + } + } + + @Test + public void testNoDupsOnSlowConsumerLargePriorityGapReconnect() throws Exception { + JmsConsumerDup consumer = new JmsConsumerDup(); + consumer.done.set(true); + consumer.run(); + + consumer.done.set(false); + JmsProvider provider = new JmsProvider(); + provider.priorityModulator = 2500; + provider.run(); + + consumer.run(); + + assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); + for (int i = 0; i < TO_RECEIVE; i++) { + assertTrue("got message " + i, dupChecker[i] == 1); + } + + } + + class JmsConsumerDup implements MessageListener { + long count = 0; + + AtomicBoolean done = new AtomicBoolean(false); + + public void run() { + Connection connection = null; + Session session; + Topic topic; + ActiveMQConnectionFactory factory; + MessageConsumer consumer; + + factory = new ActiveMQConnectionFactory(url); + + try { + connection = factory.createConnection("MyUsername", "MyPassword"); + connection.setClientID(clntId); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = session.createTopic(queueName); + consumer = session.createDurableSubscriber(topic, subscriptionName, selector, false); + consumer.setMessageListener(this); + LOG.info("Waiting for messages..."); + + while (!done.get()) { + TimeUnit.SECONDS.sleep(5); + if (count == TO_RECEIVE || !exceptions.isEmpty()) { + done.set(true); + } + } + } catch (Exception e) { + LOG.error("caught", e); + exceptions.add(e); + throw new RuntimeException(e); + } finally { + if (connection != null) { + try { + LOG.info("consumer done (" + exceptions.isEmpty() + "), closing connection"); + connection.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + } + + @Override + public void onMessage(Message message) { + ++count; + + try { + Thread.sleep(0L); + } catch (InterruptedException e) { + } + ; + + try { + TextMessage m = (TextMessage) message; + + if (count%100 == 0) { + LOG.info("Rcvd Msg #-" + count + " " + m.getText() + + " Sent->" + dtf.format(new Date(m.getJMSTimestamp())) + + " Recv->" + dtf.format(new Date()) + + " Expr->" + dtf.format(new Date(m.getJMSExpiration())) + + ", mid: " + m.getJMSMessageID() + ); + } + int i = m.getIntProperty("SeqNo"); + + //check for duplicate messages + if (i < MAX_MESSAGES) { + if (dupChecker[i] == 1) { + LOG.error("Duplicate message received at count: " + count + ", id: " + m.getJMSMessageID()); + exceptions.add(new RuntimeException("Got Duplicate at: " + m.getJMSMessageID())); + + } else { + dupChecker[i] = 1; + } + } + } catch (JMSException e) { + LOG.error("caught ", e); + exceptions.add(e); + } + } + } + + + class JmsProvider implements Runnable { + + int priorityModulator = 10; + + @Override + public void run() { + + Connection connection; + Session session; + Topic topic; + + ActiveMQConnectionFactory factory; + MessageProducer messageProducer; + long timeToLive = 0l; + + TextMessage message = null; + + factory = new ActiveMQConnectionFactory(url); + + try { + connection = factory.createConnection("MyUserName", "MyPassword"); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = session.createTopic(queueName); + messageProducer = session.createProducer(topic); + messageProducer.setPriority(3); + messageProducer.setTimeToLive(timeToLive); + messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + + int msgSeqNo = 0; + int NUM_MSGS = 1000; + int NUM_GROUPS = TO_RECEIVE/NUM_MSGS; + for (int n = 0; n < NUM_GROUPS; n++) { + + message = session.createTextMessage(); + + for (int i = 0; i < NUM_MSGS; i++) { + int priority = 0; + if (priorityModulator <= 10) { + priority = msgSeqNo % priorityModulator; + } else { + priority = (msgSeqNo >= priorityModulator) ? 9 : 0; + } + message.setText(xmlMessage + msgSeqNo + "-" + priority); + message.setJMSPriority(priority); + message.setIntProperty("SeqNo", msgSeqNo); + if (i > 0 && i%100 == 0) { + LOG.info("Sending message: " + message.getText()); + } + messageProducer.send(message, DeliveryMode.PERSISTENT, message.getJMSPriority(), timeToLive); + msgSeqNo++; + } + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + e.printStackTrace(); + exceptions.add(e); + } + } + + } catch (JMSException e) { + LOG.error("caught ", e); + e.printStackTrace(); + exceptions.add(e); + + } + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JournalDurableSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JournalDurableSubscriptionTest.java new file mode 100644 index 0000000000..8634be320e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/JournalDurableSubscriptionTest.java @@ -0,0 +1,38 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.IOException; + +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.journal.JournalPersistenceAdapterFactory; + +/** + * + */ +public class JournalDurableSubscriptionTest extends DurableSubscriptionTestSupport { + + protected PersistenceAdapter createPersistenceAdapter() throws IOException { + File dataDir = new File("target/test-data/durableJournal"); + JournalPersistenceAdapterFactory factory = new JournalPersistenceAdapterFactory(); + factory.setDataDirectoryFile(dataDir); + factory.setUseJournal(true); + factory.setJournalLogFileSize(1024 * 64); + return factory.createPersistenceAdapter(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/KahaDBDurableSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/KahaDBDurableSubscriptionTest.java new file mode 100644 index 0000000000..26faccc8fb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/KahaDBDurableSubscriptionTest.java @@ -0,0 +1,27 @@ +/** + * 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.usecases; + +import java.io.IOException; +import org.apache.activemq.store.PersistenceAdapter; + +public class KahaDBDurableSubscriptionTest extends DurableSubscriptionTestSupport { + + protected PersistenceAdapter createPersistenceAdapter() throws IOException { + return null; // use default + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/LargeQueueSparseDeleteTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/LargeQueueSparseDeleteTest.java new file mode 100644 index 0000000000..f69f1b7c69 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/LargeQueueSparseDeleteTest.java @@ -0,0 +1,200 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.filter.NonCachedMessageEvaluationContext; +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This unit test creates a fixed size queue and moves the last message in the + * queue to another queue. The test is used to very the performance of + * {@link org.apache.activemq.broker.region.Queue#moveMatchingMessagesTo(org.apache.activemq.broker.ConnectionContext, String, org.apache.activemq.command.ActiveMQDestination)}. + */ +public class LargeQueueSparseDeleteTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(LargeQueueSparseDeleteTest.class); + + /** + * {@inheritDoc} + */ + @Override + protected void setUp() throws Exception { + super.useTopic = false; + super.setUp(); + } + + /** + * The test queue is filled with QUEUE_SIZE test messages, each with a + * numeric id property beginning at 0. Once the queue is filled, the last + * message (id = QUEUE_SIZE-1) is moved to another queue. The test succeeds + * if the move completes within TEST_TIMEOUT milliseconds. + * + * @throws Exception + */ + public void testMoveMessages() throws Exception { + final int QUEUE_SIZE = 30000; + final String MOVE_TO_DESTINATION_NAME = getDestinationString() + + ".dest"; + final long TEST_TIMEOUT = 20000; + + // Populate a test queue with uniquely-identifiable messages. + Connection conn = createConnection(); + try { + conn.start(); + Session session = conn.createSession(true, + Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < QUEUE_SIZE; i++) { + Message message = session.createMessage(); + message.setIntProperty("id", i); + producer.send(message); + } + session.commit(); + } finally { + conn.close(); + } + + // Access the implementation of the test queue and move the last message + // to another queue. Verify that the move occurred within the limits of + // the test. + Queue queue = (Queue) broker.getRegionBroker().getDestinationMap().get( + destination); + + ConnectionContext context = new ConnectionContext( + new NonCachedMessageEvaluationContext()); + context.setBroker(broker.getBroker()); + context.getMessageEvaluationContext().setDestination(destination); + + long startTimeMillis = System.currentTimeMillis(); + Assert.assertEquals(1, queue + .moveMatchingMessagesTo(context, "id=" + (QUEUE_SIZE - 1), + createDestination(MOVE_TO_DESTINATION_NAME))); + + long durationMillis = System.currentTimeMillis() - startTimeMillis; + + LOG.info("It took " + durationMillis + + "ms to move the last message from a queue a " + QUEUE_SIZE + + " messages."); + + Assert.assertTrue("Moving the message took too long: " + durationMillis + + "ms", durationMillis < TEST_TIMEOUT); + } + + public void testCopyMessages() throws Exception { + final int QUEUE_SIZE = 30000; + final String MOVE_TO_DESTINATION_NAME = getDestinationString() + + ".dest"; + final long TEST_TIMEOUT = 10000; + + // Populate a test queue with uniquely-identifiable messages. + Connection conn = createConnection(); + try { + conn.start(); + Session session = conn.createSession(true, + Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < QUEUE_SIZE; i++) { + Message message = session.createMessage(); + message.setIntProperty("id", i); + producer.send(message); + } + session.commit(); + } finally { + conn.close(); + } + + // Access the implementation of the test queue and move the last message + // to another queue. Verify that the move occurred within the limits of + // the test. + Queue queue = (Queue) broker.getRegionBroker().getDestinationMap().get( + destination); + + ConnectionContext context = new ConnectionContext( + new NonCachedMessageEvaluationContext()); + context.setBroker(broker.getBroker()); + context.getMessageEvaluationContext().setDestination(destination); + + long startTimeMillis = System.currentTimeMillis(); + Assert.assertEquals(1, + queue.copyMatchingMessagesTo(context, "id=" + (QUEUE_SIZE - 1), createDestination(MOVE_TO_DESTINATION_NAME))); + + long durationMillis = System.currentTimeMillis() - startTimeMillis; + + LOG.info("It took " + durationMillis + + "ms to copy the last message from a queue a " + QUEUE_SIZE + + " messages."); + + Assert.assertTrue("Copying the message took too long: " + durationMillis + + "ms", durationMillis < TEST_TIMEOUT); + } + + public void testRemoveMessages() throws Exception { + final int QUEUE_SIZE = 30000; + final long TEST_TIMEOUT = 20000; + + // Populate a test queue with uniquely-identifiable messages. + Connection conn = createConnection(); + try { + conn.start(); + Session session = conn.createSession(true, + Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(destination); + for (int i = 0; i < QUEUE_SIZE; i++) { + Message message = session.createMessage(); + message.setIntProperty("id", i); + producer.send(message); + } + session.commit(); + } finally { + conn.close(); + } + + // Access the implementation of the test queue and move the last message + // to another queue. Verify that the move occurred within the limits of + // the test. + Queue queue = (Queue) broker.getRegionBroker().getDestinationMap().get( + destination); + + ConnectionContext context = new ConnectionContext( + new NonCachedMessageEvaluationContext()); + context.setBroker(broker.getBroker()); + context.getMessageEvaluationContext().setDestination(destination); + + long startTimeMillis = System.currentTimeMillis(); + Assert.assertEquals(1, + queue.removeMatchingMessages("id=" + (QUEUE_SIZE - 1))); + + long durationMillis = System.currentTimeMillis() - startTimeMillis; + + LOG.info("It took " + durationMillis + + "ms to remove the last message from a queue a " + QUEUE_SIZE + + " messages."); + + Assert.assertTrue("Removing the message took too long: " + durationMillis + + "ms", durationMillis < TEST_TIMEOUT); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/LevelDBDurableSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/LevelDBDurableSubscriptionTest.java new file mode 100644 index 0000000000..426b8a31eb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/LevelDBDurableSubscriptionTest.java @@ -0,0 +1,37 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.IOException; + +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.store.PersistenceAdapter; + +/** + * + */ +public class LevelDBDurableSubscriptionTest extends DurableSubscriptionTestSupport { + + protected PersistenceAdapter createPersistenceAdapter() throws IOException { + File dataDir = new File("target/test-data/durableLevelDB"); + LevelDBStore adaptor = new LevelDBStore(); + adaptor.setDirectory(dataDir); + return adaptor; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ManagedDurableSubscriptionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ManagedDurableSubscriptionTest.java new file mode 100644 index 0000000000..14fe6cb55a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ManagedDurableSubscriptionTest.java @@ -0,0 +1,119 @@ +/** + * 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.usecases; + +import java.io.File; + +import javax.jms.Connection; +import javax.jms.Session; +import javax.management.ObjectName; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.leveldb.LevelDBStore; + +public class ManagedDurableSubscriptionTest extends org.apache.activemq.TestSupport { + + BrokerService broker = null; + Connection connection = null; + ActiveMQTopic topic; + + public void testJMXSubscriptions() throws Exception { + // create durable subscription + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId"); + session.close(); + + // restart the broker + stopBroker(); + startBroker(); + + ObjectName inactiveSubscriptionObjectName = broker.getAdminView().getInactiveDurableTopicSubscribers()[0]; + + Object inactive = broker.getManagementContext().getAttribute(inactiveSubscriptionObjectName, "Active"); + assertTrue("Subscription is active.", Boolean.FALSE.equals(inactive)); + + // activate + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createDurableSubscriber(topic, "SubsId"); + + ObjectName activeSubscriptionObjectName = broker.getAdminView().getDurableTopicSubscribers()[0]; + + Object active = broker.getManagementContext().getAttribute(activeSubscriptionObjectName, "Active"); + assertTrue("Subscription is INactive.", Boolean.TRUE.equals(active)); + + // deactivate + connection.close(); + connection = null; + + inactive = broker.getManagementContext().getAttribute(inactiveSubscriptionObjectName, "Active"); + assertTrue("Subscription is active.", Boolean.FALSE.equals(inactive)); + + } + + private void startBroker() throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://localhost)"); + broker.setKeepDurableSubsActive(false); + broker.setPersistent(true); + LevelDBStore persistenceAdapter = new LevelDBStore(); + persistenceAdapter.setDirectory(new File("activemq-data/" + getName())); + broker.setPersistenceAdapter(persistenceAdapter); + broker.setUseJmx(true); + broker.getManagementContext().setCreateConnector(false); + broker.setBrokerName(getName()); + broker.start(); + + connection = createConnection(); + } + + private void stopBroker() throws Exception { + if (connection != null) + connection.close(); + connection = null; + if (broker != null) + broker.stop(); + broker = null; + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://" + getName() + "?waitForStart=5000&create=false"); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + topic = (ActiveMQTopic) createDestination(); + startBroker(); + } + + @Override + protected void tearDown() throws Exception { + stopBroker(); + super.tearDown(); + } + + @Override + protected Connection createConnection() throws Exception { + Connection rc = super.createConnection(); + rc.setClientID(getName()); + rc.start(); + return rc; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MemoryLimitTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MemoryLimitTest.java new file mode 100644 index 0000000000..49026bd6a7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MemoryLimitTest.java @@ -0,0 +1,202 @@ +/** + * 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.usecases; + +import java.util.Arrays; +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.TestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.ConsumerThread; +import org.apache.activemq.util.ProducerThread; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(value = Parameterized.class) +public class MemoryLimitTest extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(MemoryLimitTest.class); + final byte[] payload = new byte[10 * 1024]; //10KB + protected BrokerService broker; + + @Parameterized.Parameter + public TestSupport.PersistenceAdapterChoice persistenceAdapterChoice; + + @Parameterized.Parameters(name="store={0}") + public static Iterable getTestParameters() { + return Arrays.asList(new Object[][]{{TestSupport.PersistenceAdapterChoice.KahaDB}, {PersistenceAdapterChoice.LevelDB}, {PersistenceAdapterChoice.JDBC}}); + } + + protected BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.getSystemUsage().getMemoryUsage().setLimit(1 * 1024 * 1024); //1MB + broker.deleteAllMessages(); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setProducerFlowControl(false); + policyMap.put(new ActiveMQQueue(">"), policyEntry); + broker.setDestinationPolicy(policyMap); + + LOG.info("Starting broker with persistenceAdapterChoice " + persistenceAdapterChoice.toString()); + setPersistenceAdapter(broker, persistenceAdapterChoice); + broker.getPersistenceAdapter().deleteAllMessages(); + + return broker; + } + + @Override + @Before + public void setUp() throws Exception { + if (broker == null) { + broker = createBroker(); + } + broker.start(); + broker.waitUntilStarted(); + } + + @Override + @After + public void tearDown() throws Exception { + if (broker != null) { + broker.stop(); + broker.waitUntilStopped(); + } + } + + @Test(timeout = 120000) + public void testCursorBatch() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?jms.prefetchPolicy.all=10"); + factory.setOptimizeAcknowledge(true); + Connection conn = factory.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = sess.createQueue("STORE"); + final ProducerThread producer = new ProducerThread(sess, queue) { + @Override + protected Message createMessage(int i) throws Exception { + BytesMessage bytesMessage = sess.createBytesMessage(); + bytesMessage.writeBytes(payload); + return bytesMessage; + } + }; + producer.setMessageCount(2000); + producer.start(); + producer.join(); + + Thread.sleep(1000); + + // assert we didn't break high watermark (70%) usage + final Destination dest = broker.getDestination((ActiveMQQueue) queue); + LOG.info("Destination usage: " + dest.getMemoryUsage()); + int percentUsage = dest.getMemoryUsage().getPercentUsage(); + assertTrue("Should be less than 70% of limit but was: " + percentUsage, percentUsage <= 71); + LOG.info("Broker usage: " + broker.getSystemUsage().getMemoryUsage()); + assertTrue(broker.getSystemUsage().getMemoryUsage().getPercentUsage() <= 71); + + // consume one message + MessageConsumer consumer = sess.createConsumer(queue); + Message msg = consumer.receive(5000); + msg.acknowledge(); + + // this should free some space and allow us to get new batch of messages in the memory + // exceeding the limit + assertTrue("Limit is exceeded", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("Destination usage: " + dest.getMemoryUsage()); + return dest.getMemoryUsage().getPercentUsage() >= 200; + } + })); + + LOG.info("Broker usage: " + broker.getSystemUsage().getMemoryUsage()); + assertTrue(broker.getSystemUsage().getMemoryUsage().getPercentUsage() >= 200); + + // let's make sure we can consume all messages + for (int i = 1; i < 2000; i++) { + msg = consumer.receive(5000); + if (msg == null) { + dumpAllThreads("NoMessage"); + } + assertNotNull("Didn't receive message " + i, msg); + msg.acknowledge(); + } + } + + /** + * Handy test for manually checking what's going on + */ + @Ignore + @Test(timeout = 120000) + public void testLimit() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?jms.prefetchPolicy.all=10"); + factory.setOptimizeAcknowledge(true); + Connection conn = factory.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final ProducerThread producer = new ProducerThread(sess, sess.createQueue("STORE.1")) { + @Override + protected Message createMessage(int i) throws Exception { + return sess.createTextMessage(payload + "::" + i); + } + }; + producer.setMessageCount(1000); + + final ProducerThread producer2 = new ProducerThread(sess, sess.createQueue("STORE.2")) { + @Override + protected Message createMessage(int i) throws Exception { + return sess.createTextMessage(payload + "::" + i); + } + }; + producer2.setMessageCount(1000); + + ConsumerThread consumer = new ConsumerThread(sess, sess.createQueue("STORE.1")); + consumer.setBreakOnNull(false); + consumer.setMessageCount(1000); + + producer.start(); + producer.join(); + + producer2.start(); + + Thread.sleep(300); + + consumer.start(); + + consumer.join(); + producer2.join(); + + assertEquals("consumer got all produced messages", producer.getMessageCount(), consumer.getReceived()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupCloseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupCloseTest.java new file mode 100644 index 0000000000..b3341d85a5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupCloseTest.java @@ -0,0 +1,235 @@ +/** + * 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.usecases; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; +import javax.jms.Queue; +import java.util.*; +import java.util.concurrent.CountDownLatch; + +/* + * Test plan: + * Producer: publish messages into a queue, with 10 message groups, closing the group with seq=-1 on message 5 and message 10 + * Consumers: 2 consumers created after all messages are sent + * + * Expected: for each group, messages 1-5 are handled by one consumer and messages 6-10 are handled by the other consumer. Messages + * 1 and 6 have the JMSXGroupFirstForConsumer property set to true. + */ +public class MessageGroupCloseTest extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(MessageGroupNewConsumerTest.class); + private Connection connection; + // Released after all messages are created + private CountDownLatch latchMessagesCreated = new CountDownLatch(1); + + private int messagesSent, messagesRecvd1, messagesRecvd2, messageGroupCount, errorCountFirstForConsumer, errorCountWrongConsumerClose, errorCountDuplicateClose; + // groupID, count + private HashMap messageGroups1 = new HashMap(); + private HashMap messageGroups2 = new HashMap(); + private HashSet closedGroups1 = new HashSet(); + private HashSet closedGroups2 = new HashSet(); + // with the prefetch too high, this bug is not realized + private static final String connStr = + "vm://localhost?broker.persistent=false&broker.useJmx=false&jms.prefetchPolicy.all=1"; + + public void testNewConsumer() throws JMSException, InterruptedException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connStr); + connection = factory.createConnection(); + connection.start(); + final String queueName = this.getClass().getSimpleName(); + final Thread producerThread = new Thread() { + public void run() { + try { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + MessageProducer prod = session.createProducer(queue); + for (int i=0; i<10; i++) { + for (int j=0; j<10; j++) { + int seq = j + 1; + if ((j+1) % 5 == 0) { + seq = -1; + } + Message message = generateMessage(session, Integer.toString(i), seq); + prod.send(message); + session.commit(); + messagesSent++; + LOG.info("Sent message: group=" + i + ", seq="+ seq); + //Thread.sleep(20); + } + if (i % 100 == 0) { + LOG.info("Sent messages: group=" + i); + } + setMessageGroupCount(getMessageGroupCount() + 1); + } + LOG.info(messagesSent+" messages sent"); + latchMessagesCreated.countDown(); + prod.close(); + session.close(); + } catch (Exception e) { + LOG.error("Producer failed", e); + } + } + }; + final Thread consumerThread1 = new Thread() { + public void run() { + try { + latchMessagesCreated.await(); + LOG.info("starting consumer1"); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + MessageConsumer con1 = session.createConsumer(queue); + while(true) { + Message message = con1.receive(5000); + if (message == null) break; + LOG.info("Con1: got message "+formatMessage(message)); + checkMessage(message, "Con1", messageGroups1, closedGroups1); + session.commit(); + messagesRecvd1++; + if (messagesRecvd1 % 100 == 0) { + LOG.info("Con1: got messages count=" + messagesRecvd1); + } + //Thread.sleep(50); + } + LOG.info("Con1: total messages=" + messagesRecvd1); + LOG.info("Con1: total message groups=" + messageGroups1.size()); + con1.close(); + session.close(); + } catch (Exception e) { + LOG.error("Consumer 1 failed", e); + } + } + }; + final Thread consumerThread2 = new Thread() { + public void run() { + try { + latchMessagesCreated.await(); + LOG.info("starting consumer2"); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + MessageConsumer con2 = session.createConsumer(queue); + while(true) { + Message message = con2.receive(5000); + if (message == null) { break; } + LOG.info("Con2: got message "+formatMessage(message)); + checkMessage(message, "Con2", messageGroups2, closedGroups2); + session.commit(); + messagesRecvd2++; + if (messagesRecvd2 % 100 == 0) { + LOG.info("Con2: got messages count=" + messagesRecvd2); + } + //Thread.sleep(50); + } + con2.close(); + session.close(); + LOG.info("Con2: total messages=" + messagesRecvd2); + LOG.info("Con2: total message groups=" + messageGroups2.size()); + } catch (Exception e) { + LOG.error("Consumer 2 failed", e); + } + } + }; + consumerThread2.start(); + consumerThread1.start(); + producerThread.start(); + // wait for threads to finish + producerThread.join(); + consumerThread1.join(); + consumerThread2.join(); + connection.close(); + // check results + + assertEquals("consumers should get all the messages", messagesSent, messagesRecvd1 + messagesRecvd2); + assertEquals("not all message groups closed for consumer 1", messageGroups1.size(), closedGroups1.size()); + assertEquals("not all message groups closed for consumer 2", messageGroups2.size(), closedGroups2.size()); + assertTrue("producer failed to send any messages", messagesSent > 0); + assertEquals("JMSXGroupFirstForConsumer not set", 0, errorCountFirstForConsumer); + assertEquals("wrong consumer got close message", 0, errorCountWrongConsumerClose); + assertEquals("consumer got duplicate close message", 0, errorCountDuplicateClose); + } + + public Message generateMessage(Session session, String groupId, int seq) throws JMSException { + TextMessage m = session.createTextMessage(); + m.setJMSType("TEST_MESSAGE"); + m.setStringProperty("JMSXGroupID", groupId); + m.setIntProperty("JMSXGroupSeq", seq); + m.setText(""); + return m; + } + public String formatMessage(Message m) { + try { + return "group="+m.getStringProperty("JMSXGroupID")+", seq="+m.getIntProperty("JMSXGroupSeq"); + } catch (Exception e) { + return e.getClass().getSimpleName()+": "+e.getMessage(); + } + } + public void checkMessage(Message m, String consumerId, Map messageGroups, Set closedGroups) throws JMSException { + String groupId = m.getStringProperty("JMSXGroupID"); + int seq = m.getIntProperty("JMSXGroupSeq"); + Integer count = messageGroups.get(groupId); + if (count == null) { + // first time seeing this group + if (!m.propertyExists("JMSXGroupFirstForConsumer") || + !m.getBooleanProperty("JMSXGroupFirstForConsumer")) { + LOG.info(consumerId + ": JMSXGroupFirstForConsumer not set for group=" + groupId + ", seq=" +seq); + errorCountFirstForConsumer++; + } + if (seq == -1) { + closedGroups.add(groupId); + LOG.info(consumerId + ": wrong consumer got close message for group=" + groupId); + errorCountWrongConsumerClose++; + } + messageGroups.put(groupId, 1); + } else { + // existing group + if (closedGroups.contains(groupId)) { + // group reassigned to same consumer + closedGroups.remove(groupId); + if (!m.propertyExists("JMSXGroupFirstForConsumer") || + !m.getBooleanProperty("JMSXGroupFirstForConsumer")) { + LOG.info(consumerId + ": JMSXGroupFirstForConsumer not set for group=" + groupId + ", seq=" +seq); + errorCountFirstForConsumer++; + } + if (seq == -1) { + LOG.info(consumerId + ": consumer got duplicate close message for group=" + groupId); + errorCountDuplicateClose++; + } + } + if (seq == -1) { + closedGroups.add(groupId); + } + messageGroups.put(groupId, count + 1); + } + } + + /** + * @return the messageGroupCount + */ + public int getMessageGroupCount() { + return messageGroupCount; + } + + /** + * @param messageGroupCount the messageGroupCount to set + */ + public void setMessageGroupCount(int messageGroupCount) { + this.messageGroupCount = messageGroupCount; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupDelayedTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupDelayedTest.java new file mode 100644 index 0000000000..bb20e420a7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupDelayedTest.java @@ -0,0 +1,243 @@ +/** + * 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.usecases; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageGroupDelayedTest extends JmsTestSupport { + public static final Logger log = LoggerFactory.getLogger(MessageGroupDelayedTest.class); + protected Connection connection; + protected Session session; + protected MessageProducer producer; + protected Destination destination; + + public int consumersBeforeDispatchStarts; + public int timeBeforeDispatchStarts; + + BrokerService broker; + protected TransportConnector connector; + + protected HashMap messageCount = new HashMap(); + protected HashMap> messageGroups = new HashMap>(); + + public static Test suite() { + return suite(MessageGroupDelayedTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + @Override + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + ActiveMQConnectionFactory connFactory = new ActiveMQConnectionFactory(connector.getConnectUri() + "?jms.prefetchPolicy.all=1"); + connection = connFactory.createConnection(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = new ActiveMQQueue("test-queue2"); + producer = session.createProducer(destination); + connection.start(); + } + + @Override + protected BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + + // Setup a destination policy where it takes only 1 message at a time. + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + log.info("testing with consumersBeforeDispatchStarts=" + consumersBeforeDispatchStarts + " and timeBeforeDispatchStarts=" + timeBeforeDispatchStarts); + policy.setConsumersBeforeDispatchStarts(consumersBeforeDispatchStarts); + policy.setTimeBeforeDispatchStarts(timeBeforeDispatchStarts); + policyMap.setDefaultEntry(policy); + service.setDestinationPolicy(policyMap); + + connector = service.addConnector("tcp://localhost:0"); + return service; + } + + @Override + public void tearDown() throws Exception { + producer.close(); + session.close(); + connection.close(); + broker.stop(); + } + + public void initCombosForTestDelayedDirectConnectionListener() { + addCombinationValues("consumersBeforeDispatchStarts", new Object[] { 0, 3, 5 }); + addCombinationValues("timeBeforeDispatchStarts", new Object[] { 0, 100 }); + } + + public void testDelayedDirectConnectionListener() throws Exception { + + for (int i = 0; i < 10; i++) { + Message msga = session.createTextMessage("hello a"); + msga.setStringProperty("JMSXGroupID", "A"); + producer.send(msga); + Message msgb = session.createTextMessage("hello b"); + msgb.setStringProperty("JMSXGroupID", "B"); + producer.send(msgb); + Message msgc = session.createTextMessage("hello c"); + msgc.setStringProperty("JMSXGroupID", "C"); + producer.send(msgc); + } + log.info("30 messages sent to group A/B/C"); + + int[] counters = { 10, 10, 10 }; + + CountDownLatch startSignal = new CountDownLatch(1); + CountDownLatch doneSignal = new CountDownLatch(1); + + messageCount.put("worker1", 0); + messageGroups.put("worker1", new HashSet()); + Worker worker1 = new Worker(connection, destination, "worker1", startSignal, doneSignal, counters, messageCount, messageGroups); + messageCount.put("worker2", 0); + messageGroups.put("worker2", new HashSet()); + Worker worker2 = new Worker(connection, destination, "worker2", startSignal, doneSignal, counters, messageCount, messageGroups); + messageCount.put("worker3", 0); + messageGroups.put("worker3", new HashSet()); + Worker worker3 = new Worker(connection, destination, "worker3", startSignal, doneSignal, counters, messageCount, messageGroups); + + new Thread(worker1).start(); + new Thread(worker2).start(); + new Thread(worker3).start(); + + startSignal.countDown(); + doneSignal.await(); + + // check results + if (consumersBeforeDispatchStarts == 0 && timeBeforeDispatchStarts == 0) { + log.info("Ignoring results because both parameters are 0"); + return; + } + + for (String worker : messageCount.keySet()) { + log.info("worker " + worker + " received " + messageCount.get(worker) + " messages from groups " + messageGroups.get(worker)); + assertEquals("worker " + worker + " received " + messageCount.get(worker) + " messages from groups " + messageGroups.get(worker), 10, messageCount + .get(worker).intValue()); + assertEquals("worker " + worker + " received " + messageCount.get(worker) + " messages from groups " + messageGroups.get(worker), 1, messageGroups + .get(worker).size()); + } + + } + + private static final class Worker implements Runnable { + private Connection connection = null; + private Destination queueName = null; + private String workerName = null; + private CountDownLatch startSignal = null; + private CountDownLatch doneSignal = null; + private int[] counters = null; + private final HashMap messageCount; + private final HashMap> messageGroups; + + private Worker(Connection connection, Destination queueName, String workerName, CountDownLatch startSignal, CountDownLatch doneSignal, int[] counters, + HashMap messageCount, HashMap> messageGroups) { + this.connection = connection; + this.queueName = queueName; + this.workerName = workerName; + this.startSignal = startSignal; + this.doneSignal = doneSignal; + this.counters = counters; + this.messageCount = messageCount; + this.messageGroups = messageGroups; + } + + private void update(String group) { + int msgCount = messageCount.get(workerName); + messageCount.put(workerName, msgCount + 1); + Set groups = messageGroups.get(workerName); + groups.add(group); + messageGroups.put(workerName, groups); + } + + @Override + public void run() { + + try { + log.info(workerName); + startSignal.await(); + Session sess = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = sess.createConsumer(queueName); + + while (true) { + if (counters[0] == 0 && counters[1] == 0 && counters[2] == 0) { + doneSignal.countDown(); + log.info(workerName + " done..."); + break; + } + + Message msg = consumer.receive(500); + if (msg == null) + continue; + + String group = msg.getStringProperty("JMSXGroupID"); + msg.getBooleanProperty("JMSXGroupFirstForConsumer"); + + if ("A".equals(group)) { + --counters[0]; + update(group); + Thread.sleep(500); + } else if ("B".equals(group)) { + --counters[1]; + update(group); + Thread.sleep(100); + } else if ("C".equals(group)) { + --counters[2]; + update(group); + Thread.sleep(10); + } else { + log.warn("unknown group"); + } + if (counters[0] != 0 || counters[1] != 0 || counters[2] != 0) { + msg.acknowledge(); + } + } + consumer.close(); + sess.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupLateArrivalsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupLateArrivalsTest.java new file mode 100644 index 0000000000..7a9b410a90 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupLateArrivalsTest.java @@ -0,0 +1,303 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.*; + +@RunWith(BlockJUnit4ClassRunner.class) +public class MessageGroupLateArrivalsTest { + public static final Logger log = LoggerFactory.getLogger(MessageGroupLateArrivalsTest.class); + protected Connection connection; + protected Session session; + protected MessageProducer producer; + protected Destination destination; + + BrokerService broker; + protected TransportConnector connector; + + protected HashMap messageCount = new HashMap(); + protected HashMap> messageGroups = new HashMap>(); + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + ActiveMQConnectionFactory connFactory = new ActiveMQConnectionFactory(connector.getConnectUri() + "?jms.prefetchPolicy.all=1000"); + connection = connFactory.createConnection(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = new ActiveMQQueue("test-queue2"); + producer = session.createProducer(destination); + connection.start(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setPersistent(false); + service.setUseJmx(false); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setUseConsumerPriority(true); + policyMap.setDefaultEntry(policy); + service.setDestinationPolicy(policyMap); + + connector = service.addConnector("tcp://localhost:0"); + return service; + } + + @After + public void tearDown() throws Exception { + producer.close(); + session.close(); + connection.close(); + broker.stop(); + } + + @Test(timeout = 30 * 1000) + public void testConsumersLateToThePartyGetSomeNewGroups() throws Exception { + + final int perBatch = 3; + int[] counters = {perBatch, perBatch, perBatch}; + + CountDownLatch startSignal = new CountDownLatch(0); + CountDownLatch doneSignal = new CountDownLatch(3); + CountDownLatch worker1Started = new CountDownLatch(1); + CountDownLatch worker2Started = new CountDownLatch(1); + CountDownLatch worker3Started = new CountDownLatch(1); + + messageCount.put("worker1", 0); + messageGroups.put("worker1", new HashSet()); + Worker worker1 = new Worker(connection, destination, "worker1", startSignal, doneSignal, counters, messageCount, messageGroups, worker1Started); + messageCount.put("worker2", 0); + messageGroups.put("worker2", new HashSet()); + Worker worker2 = new Worker(connection, destination, "worker2", startSignal, doneSignal, counters, messageCount, messageGroups, worker2Started); + messageCount.put("worker3", 0); + messageGroups.put("worker3", new HashSet()); + Worker worker3 = new Worker(connection, destination, "worker3", startSignal, doneSignal, counters, messageCount, messageGroups, worker3Started); + + new Thread(worker1).start(); + new Thread(worker2).start(); + worker1Started.await(); + worker2Started.await(); + + for (int i = 0; i < perBatch; i++) { + Message msga = session.createTextMessage("hello a"); + msga.setStringProperty("JMSXGroupID", "A"); + producer.send(msga); + + Message msgb = session.createTextMessage("hello b"); + msgb.setStringProperty("JMSXGroupID", "B"); + producer.send(msgb); + } + + // ensure this chap, late to the party gets a new group + new Thread(worker3).start(); + + // wait for presence before new group + worker3Started.await(); + + for (int i = 0; i < perBatch; i++) { + Message msgc = session.createTextMessage("hello c"); + msgc.setStringProperty("JMSXGroupID", "C"); + producer.send(msgc); + } + + doneSignal.await(); + + List workers = new ArrayList(messageCount.keySet()); + Collections.sort(workers); + for (String worker : workers) { + log.info("worker " + worker + " received " + messageCount.get(worker) + " messages from groups " + messageGroups.get(worker)); + } + + for (String worker : workers) { + assertEquals("worker " + worker + " received " + messageCount.get(worker) + " messages from groups " + messageGroups.get(worker) + , perBatch, messageCount.get(worker).intValue()); + assertEquals("worker " + worker + " received " + messageCount.get(worker) + " messages from groups " + messageGroups.get(worker) + , 1, messageGroups.get(worker).size()); + } + } + + @Test(timeout = 30 * 1000) + public void testConsumerLateToBigPartyGetsNewGroup() throws Exception { + + final int perBatch = 2; + int[] counters = {perBatch, perBatch, perBatch}; + + CountDownLatch startSignal = new CountDownLatch(0); + CountDownLatch doneSignal = new CountDownLatch(2); + CountDownLatch worker1Started = new CountDownLatch(1); + CountDownLatch worker2Started = new CountDownLatch(1); + + messageCount.put("worker1", 0); + messageGroups.put("worker1", new HashSet()); + Worker worker1 = new Worker(connection, destination, "worker1", startSignal, doneSignal, counters, messageCount, messageGroups, worker1Started); + messageCount.put("worker2", 0); + messageGroups.put("worker2", new HashSet()); + Worker worker2 = new Worker(connection, destination, "worker2", startSignal, doneSignal, counters, messageCount, messageGroups, worker2Started); + + new Thread(worker1).start(); + + for (int i = 0; i < perBatch; i++) { + Message msga = session.createTextMessage("hello c"); + msga.setStringProperty("JMSXGroupID", "A"); + producer.send(msga); + + Message msgb = session.createTextMessage("hello b"); + msgb.setStringProperty("JMSXGroupID", "B"); + producer.send(msgb); + } + + // ensure this chap, late to the party gets a new group + new Thread(worker2).start(); + + // wait for presence before new group + worker2Started.await(); + + for (int i = 0; i < perBatch; i++) { + Message msgc = session.createTextMessage("hello a"); + msgc.setStringProperty("JMSXGroupID", "C"); + producer.send(msgc); + } + + doneSignal.await(); + + log.info("worker1 received " + messageCount.get("worker1") + " messages from groups " + messageGroups.get("worker1")); + assertEquals("worker1 received " + messageCount.get("worker1") + " messages from groups " + messageGroups.get("worker1") + , 2 * perBatch, messageCount.get("worker1").intValue()); + assertEquals("worker1 received " + messageCount.get("worker1") + " messages from groups " + messageGroups.get("worker1") + , 2, messageGroups.get("worker1").size()); + + log.info("worker2 received " + messageCount.get("worker2") + " messages from groups " + messageGroups.get("worker2")); + assertEquals("worker2 received " + messageCount.get("worker2") + " messages from groups " + messageGroups.get("worker2") + , 2 * perBatch, messageCount.get("worker1").intValue()); + assertEquals("worker2 received " + messageCount.get("worker2") + " messages from groups " + messageGroups.get("worker2") + , 1, messageGroups.get("worker2").size()); + } + + private static final class Worker implements Runnable { + private Connection connection = null; + private Destination queueName = null; + private String workerName = null; + private CountDownLatch startSignal = null; + private CountDownLatch doneSignal = null; + private CountDownLatch workerStarted = null; + private int[] counters = null; + private final HashMap messageCount; + private final HashMap> messageGroups; + + private Worker(Connection connection, Destination queueName, String workerName, CountDownLatch startSignal, CountDownLatch doneSignal, + int[] counters, HashMap messageCount, HashMap> messageGroups, CountDownLatch workerStarted) { + this.connection = connection; + this.queueName = queueName; + this.workerName = workerName; + this.startSignal = startSignal; + this.doneSignal = doneSignal; + this.counters = counters; + this.messageCount = messageCount; + this.messageGroups = messageGroups; + this.workerStarted = workerStarted; + } + + private void update(String group) { + int msgCount = messageCount.get(workerName); + messageCount.put(workerName, msgCount + 1); + Set groups = messageGroups.get(workerName); + groups.add(group); + messageGroups.put(workerName, groups); + } + + @Override + public void run() { + + try { + startSignal.await(); + log.info(workerName); + Session sess = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = sess.createConsumer(queueName); + workerStarted.countDown(); + + while (true) { + if (counters[0] == 0 && counters[1] == 0 && counters[2] == 0) { + doneSignal.countDown(); + log.info(workerName + " done..."); + break; + } + + Message msg = consumer.receive(500); + if (msg == null) + continue; + + msg.acknowledge(); + + String group = msg.getStringProperty("JMSXGroupID"); + msg.getBooleanProperty("JMSXGroupFirstForConsumer"); + + if ("A".equals(group)) { + --counters[0]; + update(group); + } else if ("B".equals(group)) { + --counters[1]; + update(group); + } else if ("C".equals(group)) { + --counters[2]; + update(group); + } else { + log.warn(workerName + ", unknown group"); + } + if (counters[0] != 0 || counters[1] != 0 || counters[2] != 0) { + msg.acknowledge(); + } + } + consumer.close(); + sess.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupNewConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupNewConsumerTest.java new file mode 100644 index 0000000000..5d43f66510 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupNewConsumerTest.java @@ -0,0 +1,178 @@ +/** + * 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.usecases; + +import java.util.concurrent.CountDownLatch; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import junit.framework.TestCase; + +/* + * Test plan: + * Producer: publish messages into a queue, with three message groups + * Consumer1: created before any messages are created + * Consumer2: created after consumer1 has processed one message from each message group + * + * All three groups are handled by to consumer1, so consumer2 should not get any messages. + * See bug AMQ-2016: Message grouping fails when consumers are added + */ +public class MessageGroupNewConsumerTest extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(MessageGroupNewConsumerTest.class); + private Connection connection; + // Released after the messages are created + private CountDownLatch latchMessagesCreated = new CountDownLatch(1); + // Released after one message from each group is consumed + private CountDownLatch latchGroupsAcquired = new CountDownLatch(1); + + private static final String[] groupNames = { "GrA", "GrB", "GrC" }; + private int messagesSent, messagesRecvd1, messagesRecvd2; + // with the prefetch too high, this bug is not realized + private static final String connStr = "vm://localhost?broker.persistent=false&broker.useJmx=false&jms.prefetchPolicy.all=1"; + + public void testNewConsumer() throws JMSException, InterruptedException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connStr); + connection = factory.createConnection(); + connection.start(); + final String queueName = this.getClass().getSimpleName(); + final Thread producerThread = new Thread() { + public void run() { + try { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + MessageProducer prod = session.createProducer(queue); + for (int i=0; i<10; i++) { + for(String group : groupNames) { + Message message = generateMessage(session, group, i+1); + prod.send(message); + session.commit(); + messagesSent++; + } + LOG.info("Sent message seq "+ (i+1)); + if (i==0) { + latchMessagesCreated.countDown(); + } + if (i==2) { + LOG.info("Prod: Waiting for groups"); + latchGroupsAcquired.await(); + } + Thread.sleep(20); + } + LOG.info(messagesSent+" messages sent"); + prod.close(); + session.close(); + } catch (Exception e) { + LOG.error("Producer failed", e); + } + } + }; + final Thread consumerThread1 = new Thread() { + public void run() { + try { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + MessageConsumer con1 = session.createConsumer(queue); + latchMessagesCreated.await(); + while(true) { + Message message = con1.receive(1000); + if (message == null) break; + LOG.info("Con1 got message "+formatMessage(message)); + session.commit(); + messagesRecvd1++; + // since we get the messages in order, the first few messages will be one from each group + // after we get one from each group, start the other consumer + if (messagesRecvd1 == groupNames.length) { + LOG.info("All groups acquired"); + latchGroupsAcquired.countDown(); + Thread.sleep(1000); + } + Thread.sleep(50); + } + LOG.info(messagesRecvd1+" messages received by consumer1"); + con1.close(); + session.close(); + } catch (Exception e) { + LOG.error("Consumer 1 failed", e); + } + } + }; + final Thread consumerThread2 = new Thread() { + public void run() { + try { + latchGroupsAcquired.await(); + while(consumerThread1.isAlive()) { + LOG.info("(re)starting consumer2"); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + MessageConsumer con2 = session.createConsumer(queue); + while(true) { + Message message = con2.receive(500); + if (message == null) break; + LOG.info("Con2 got message "+formatMessage(message)); + session.commit(); + messagesRecvd2++; + Thread.sleep(50); + } + con2.close(); + session.close(); + } + LOG.info(messagesRecvd2+" messages received by consumer2"); + } catch (Exception e) { + LOG.error("Consumer 2 failed", e); + } + } + }; + consumerThread2.start(); + consumerThread1.start(); + producerThread.start(); + // wait for threads to finish + producerThread.join(); + consumerThread1.join(); + consumerThread2.join(); + connection.close(); + // check results + assertEquals("consumer 2 should not get any messages", 0, messagesRecvd2); + assertEquals("consumer 1 should get all the messages", messagesSent, messagesRecvd1); + assertTrue("producer failed to send any messages", messagesSent > 0); + } + + public Message generateMessage(Session session, String groupId, int seq) throws JMSException { + TextMessage m = session.createTextMessage(); + m.setJMSType("TEST_MESSAGE"); + m.setStringProperty("JMSXGroupID", groupId); + m.setIntProperty("JMSXGroupSeq", seq); + m.setText(""); + return m; + } + public String formatMessage(Message m) { + try { + return m.getStringProperty("JMSXGroupID")+"-"+m.getIntProperty("JMSXGroupSeq")+"-"+m.getBooleanProperty("JMSXGroupFirstForConsumer"); + } catch (Exception e) { + return e.getClass().getSimpleName()+": "+e.getMessage(); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupReconnectDistributionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupReconnectDistributionTest.java new file mode 100644 index 0000000000..da2f367c48 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageGroupReconnectDistributionTest.java @@ -0,0 +1,218 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(Parameterized.class) +public class MessageGroupReconnectDistributionTest { + public static final Logger LOG = LoggerFactory.getLogger(MessageGroupReconnectDistributionTest.class); + final Random random = new Random(); + protected Connection connection; + protected Session session; + protected MessageProducer producer; + protected ActiveMQQueue destination = new ActiveMQQueue("GroupQ"); + protected TransportConnector connector; + ActiveMQConnectionFactory connFactory; + BrokerService broker; + int numMessages = 10000; + int groupSize = 10; + int batchSize = 20; + + @Parameterized.Parameter(0) + public int numConsumers = 4; + + @Parameterized.Parameter(1) + public boolean consumerPriority = true; + + @Parameterized.Parameters(name="numConsumers={0},consumerPriority={1}") + public static Iterable combinations() { + return Arrays.asList(new Object[][]{{4, true}, {10, true}}); + } + + @Before + public void setUp() throws Exception { + broker = createBroker(); + broker.start(); + connFactory = new ActiveMQConnectionFactory(connector.getConnectUri() + "?jms.prefetchPolicy.all=200"); + connFactory.setWatchTopicAdvisories(false); + connection = connFactory.createConnection(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + producer = session.createProducer(destination); + connection.start(); + } + + protected BrokerService createBroker() throws Exception { + BrokerService service = new BrokerService(); + service.setAdvisorySupport(false); + service.setPersistent(false); + service.setUseJmx(true); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setUseConsumerPriority(consumerPriority); + policy.setMessageGroupMapFactoryType("cached?cacheSize=" + (numConsumers - 1)); + policyMap.setDefaultEntry(policy); + service.setDestinationPolicy(policyMap); + + connector = service.addConnector("tcp://localhost:0"); + return service; + } + + @After + public void tearDown() throws Exception { + producer.close(); + session.close(); + connection.close(); + broker.stop(); + } + + @Test(timeout = 5 * 60 * 1000) + public void testReconnect() throws Exception { + + final AtomicLong totalConsumed = new AtomicLong(0); + + ExecutorService executorService = Executors.newFixedThreadPool(numConsumers); + final ArrayList consumedCounters = new ArrayList(numConsumers); + final ArrayList batchCounters = new ArrayList(numConsumers); + + for (int i = 0; i < numConsumers; i++) { + consumedCounters.add(new AtomicLong(0l)); + batchCounters.add(new AtomicLong(0l)); + + final int id = i; + executorService.submit(new Runnable() { + int getBatchSize() { + return (id + 1) * batchSize; + } + + @Override + public void run() { + try { + Session connectionSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + int batchSize = getBatchSize(); + MessageConsumer messageConsumer = connectionSession.createConsumer(destWithPrefetch(destination)); + + Message message; + AtomicLong consumed = consumedCounters.get(id); + AtomicLong batches = batchCounters.get(id); + + LOG.info("Consumer: " + id + ", batchSize:" + batchSize + ", totalConsumed:" + totalConsumed.get() + ", consumed:" + consumed.get()); + + while (totalConsumed.get() < numMessages) { + + message = messageConsumer.receive(10000); + + if (message == null) { + LOG.info("Consumer: " + id + ", batchSize:" + batchSize + ", null message (totalConsumed:" + totalConsumed.get() + ") consumed:" + consumed.get()); + messageConsumer.close(); + + if (totalConsumed.get() == numMessages) { + break; + } else { + batchSize = getBatchSize(); + messageConsumer = connectionSession.createConsumer(destWithPrefetch(destination)); + batches.incrementAndGet(); + continue; + } + } + + consumed.incrementAndGet(); + totalConsumed.incrementAndGet(); + + if (consumed.get() > 0 && consumed.intValue() % batchSize == 0) { + messageConsumer.close(); + batchSize = getBatchSize(); + messageConsumer = connectionSession.createConsumer(destWithPrefetch(destination)); + batches.incrementAndGet(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + TimeUnit.MILLISECONDS.sleep(200); + } + + TimeUnit.SECONDS.sleep(1); + produceMessages(numMessages); + + executorService.shutdown(); + assertTrue("threads done on time", executorService.awaitTermination(10, TimeUnit.MINUTES)); + + assertEquals("All consumed", numMessages, totalConsumed.intValue()); + + LOG.info("Distribution: " + consumedCounters); + LOG.info("Batches: " + batchCounters); + + double max = consumedCounters.get(0).longValue() * 1.5; + double min = consumedCounters.get(0).longValue() * 0.5; + + for (AtomicLong l : consumedCounters) { + assertTrue("Even +/- 50% distribution on consumed:" + consumedCounters + ", outlier:" + l.get(), + l.longValue() < max && l.longValue() > min); + } + } + + private Destination destWithPrefetch(ActiveMQQueue destination) throws Exception { + return destination; + } + + private void produceMessages(int numMessages) throws JMSException { + int groupID=0; + for (int i = 0; i < numMessages; i++) { + if (i>0 && i%groupSize==0) { + groupID++; + } + TextMessage msga = session.createTextMessage("hello " + i); + msga.setStringProperty("JMSXGroupID", "Group-"+groupID); + producer.send(msga); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageReroutingTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageReroutingTest.java new file mode 100644 index 0000000000..8a83ee382a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MessageReroutingTest.java @@ -0,0 +1,87 @@ +/** + * 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.usecases; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; + +import junit.framework.Test; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +public class MessageReroutingTest extends JmsMultipleBrokersTestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(MessageReroutingTest.class); + + + public Destination dest; + public static final int MESSAGE_COUNT = 50; + + protected void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + + createBroker(new ClassPathResource("org/apache/activemq/usecases/rerouting-activemq-D.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/rerouting-activemq-C.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/rerouting-activemq-B.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/rerouting-activemq-A.xml")); + + brokers.get("broker-A").broker.waitUntilStarted(); + } + + public void initCombos() { + addCombinationValues("dest", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST")}); + } + + public void testMessageRerouting() throws Exception { + MessageConsumer consumer = createConsumer("broker-D", dest); + + MessageIdList received = getConsumerMessages("broker-D", consumer); + + Thread.sleep(2000); //wait for subs to propagate + + // send/receive messages + sendMessages("broker-A", dest, MESSAGE_COUNT); + received.waitForMessagesToArrive(MESSAGE_COUNT); + LOG.info("received " + received.getMessageCount() + " messages"); + assertEquals(MESSAGE_COUNT, received.getMessageCount()); + + brokers.get("broker-B").broker.stop(); + brokers.get("broker-B").broker.waitUntilStopped(); + Thread.sleep(2000); + + // ensure send/receive still works + sendMessages("broker-A", dest, MESSAGE_COUNT); + received.waitForMessagesToArrive(MESSAGE_COUNT); + LOG.info("received " + received.getMessageCount() + " messages"); + assertTrue("Didn't receive any more messages " + received.getMessageCount(), received.getMessageCount() > MESSAGE_COUNT); + + + } + + + public static Test suite() { + return suite(MessageReroutingTest.class); + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MultiBrokersMultiClientsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MultiBrokersMultiClientsTest.java new file mode 100644 index 0000000000..bd5c4c89ce --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MultiBrokersMultiClientsTest.java @@ -0,0 +1,166 @@ +/** + * 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.usecases; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class MultiBrokersMultiClientsTest extends JmsMultipleBrokersTestSupport implements UncaughtExceptionHandler { + public static final int BROKER_COUNT = 6; // number of brokers to network + public static final int CONSUMER_COUNT = 25; // consumers per broker + public static final int PRODUCER_COUNT = 3; // producers per broker + public static final int MESSAGE_COUNT = 20; // messages per producer + + private static final Logger LOG = LoggerFactory.getLogger(MultiBrokersMultiClientsTest.class); + + protected Map consumerMap; + Map unhandeledExceptions = new HashMap(); + + public void testTopicAllConnected() throws Exception { + bridgeAllBrokers(); + startAllBrokers(); + waitForBridgeFormation(); + + // Setup topic destination + Destination dest = createDestination("TEST.FOO", true); + + CountDownLatch latch = new CountDownLatch(BROKER_COUNT * PRODUCER_COUNT * BROKER_COUNT * CONSUMER_COUNT * MESSAGE_COUNT); + + // Setup consumers + for (int i = 1; i <= BROKER_COUNT; i++) { + for (int j = 0; j < CONSUMER_COUNT; j++) { + consumerMap.put("Consumer:" + i + ":" + j, createConsumer("Broker" + i, dest, latch)); + } + } + + // wait for consumers to get propagated + for (int i = 1; i <= BROKER_COUNT; i++) { + // all consumers on the remote brokers look like 1 consumer to the local broker. + assertConsumersConnect("Broker" + i, dest, (BROKER_COUNT-1)+CONSUMER_COUNT, 65000); + } + + // Send messages + for (int i = 1; i <= BROKER_COUNT; i++) { + for (int j = 0; j < PRODUCER_COUNT; j++) { + sendMessages("Broker" + i, dest, MESSAGE_COUNT); + } + } + + assertTrue("Missing " + latch.getCount() + " messages", latch.await(45, TimeUnit.SECONDS)); + + // Get message count + for (int i = 1; i <= BROKER_COUNT; i++) { + for (int j = 0; j < CONSUMER_COUNT; j++) { + MessageIdList msgs = getConsumerMessages("Broker" + i, (MessageConsumer)consumerMap.get("Consumer:" + i + ":" + j)); + assertEquals(BROKER_COUNT * PRODUCER_COUNT * MESSAGE_COUNT, msgs.getMessageCount()); + } + } + + assertNoUnhandeledExceptions(); + } + + private void assertNoUnhandeledExceptions() { + for( Entry e: unhandeledExceptions.entrySet()) { + LOG.error("Thread:" + e.getKey() + " Had unexpected: " + e.getValue()); + } + assertTrue("There are no unhandelled exceptions, see: log for detail on: " + unhandeledExceptions, + unhandeledExceptions.isEmpty()); + } + + public void testQueueAllConnected() throws Exception { + bridgeAllBrokers(); + startAllBrokers(); + this.waitForBridgeFormation(); + + // Setup topic destination + Destination dest = createDestination("TEST.FOO", false); + + CountDownLatch latch = new CountDownLatch(BROKER_COUNT * PRODUCER_COUNT * MESSAGE_COUNT); + + // Setup consumers + for (int i = 1; i <= BROKER_COUNT; i++) { + for (int j = 0; j < CONSUMER_COUNT; j++) { + consumerMap.put("Consumer:" + i + ":" + j, createConsumer("Broker" + i, dest, latch)); + } + } + + // wait for consumers to get propagated + for (int i = 1; i <= BROKER_COUNT; i++) { + // all consumers on the remote brokers look like 1 consumer to the local broker. + assertConsumersConnect("Broker" + i, dest, (BROKER_COUNT-1)+CONSUMER_COUNT, 65000); + } + + // Send messages + for (int i = 1; i <= BROKER_COUNT; i++) { + for (int j = 0; j < PRODUCER_COUNT; j++) { + sendMessages("Broker" + i, dest, MESSAGE_COUNT); + } + } + + // Wait for messages to be delivered + assertTrue("Missing " + latch.getCount() + " messages", latch.await(45, TimeUnit.SECONDS)); + + // Get message count + int totalMsg = 0; + for (int i = 1; i <= BROKER_COUNT; i++) { + for (int j = 0; j < CONSUMER_COUNT; j++) { + MessageIdList msgs = getConsumerMessages("Broker" + i, consumerMap.get("Consumer:" + i + ":" + j)); + totalMsg += msgs.getMessageCount(); + } + } + assertEquals(BROKER_COUNT * PRODUCER_COUNT * MESSAGE_COUNT, totalMsg); + + assertNoUnhandeledExceptions(); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + + unhandeledExceptions.clear(); + Thread.setDefaultUncaughtExceptionHandler(this); + + // Setup n brokers + for (int i = 1; i <= BROKER_COUNT; i++) { + createBroker(new URI("broker:()/Broker" + i + "?persistent=false&useJmx=false")); + } + + consumerMap = new HashMap(); + } + + public void uncaughtException(Thread t, Throwable e) { + synchronized(unhandeledExceptions) { + unhandeledExceptions.put(t,e); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MultiBrokersMultiClientsUsingTcpTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MultiBrokersMultiClientsUsingTcpTest.java new file mode 100644 index 0000000000..23cf042107 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MultiBrokersMultiClientsUsingTcpTest.java @@ -0,0 +1,86 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.DemandForwardingBridge; +import org.apache.activemq.network.NetworkBridgeConfiguration; +import org.apache.activemq.transport.TransportFactory; + +/** + * + */ +public class MultiBrokersMultiClientsUsingTcpTest extends MultiBrokersMultiClientsTest { + protected List bridges; + + protected void bridgeAllBrokers(String groupName) throws Exception { + for (int i = 1; i <= BROKER_COUNT; i++) { + for (int j = 1; j <= BROKER_COUNT; j++) { + if (i != j) { + bridgeBrokers("Broker" + i, "Broker" + j); + } + } + } + + maxSetupTime = 5000; + } + + protected void bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker) throws Exception { + List remoteTransports = remoteBroker.getTransportConnectors(); + List localTransports = localBroker.getTransportConnectors(); + + URI remoteURI; + URI localURI; + if (!remoteTransports.isEmpty() && !localTransports.isEmpty()) { + remoteURI = remoteTransports.get(0).getConnectUri(); + localURI = localTransports.get(0).getConnectUri(); + + // Ensure that we are connecting using tcp + if (remoteURI.toString().startsWith("tcp:") && localURI.toString().startsWith("tcp:")) { + NetworkBridgeConfiguration config = new NetworkBridgeConfiguration(); + config.setBrokerName(localBroker.getBrokerName()); + DemandForwardingBridge bridge = new DemandForwardingBridge(config, TransportFactory.connect(localURI), TransportFactory.connect(remoteURI)); + bridge.setBrokerService(localBroker); + bridges.add(bridge); + + bridge.start(); + } else { + throw new Exception("Remote broker or local broker is not using tcp connectors"); + } + } else { + throw new Exception("Remote broker or local broker has no registered connectors."); + } + } + + public void setUp() throws Exception { + super.setUp(); + + // Assign a tcp connector to each broker + int j = 0; + for (Iterator i = brokers.values().iterator(); i.hasNext();) { + i.next().broker.addConnector("tcp://localhost:" + (61616 + j++)); + } + + bridges = new ArrayList(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MulticastDiscoveryOnFaultyNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MulticastDiscoveryOnFaultyNetworkTest.java new file mode 100644 index 0000000000..e911d0c348 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MulticastDiscoveryOnFaultyNetworkTest.java @@ -0,0 +1,130 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.List; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.TextMessage; + +import junit.framework.Test; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.MessageIdList; + + +public class MulticastDiscoveryOnFaultyNetworkTest extends JmsMultipleBrokersTestSupport { + protected static final int MESSAGE_COUNT = 200; + private static final String HUB = "HubBroker"; + private static final String SPOKE = "SpokeBroker"; + public boolean useDuplexNetworkBridge = true; + public boolean useStaticDiscovery = false; + + public void initCombosForTestSendOnAFaultyTransport() { + addCombinationValues( "useDuplexNetworkBridge", new Object[]{ Boolean.TRUE , Boolean.FALSE } ); + addCombinationValues( "useStaticDiscovery", new Object[]{ Boolean.TRUE , Boolean.FALSE } ); + } + + public void testSendOnAFaultyTransport() throws Exception { + bridgeBrokers(SPOKE, HUB); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer client = createConsumer(HUB, dest); + + // allow subscription information to flow back to Spoke + sleep(600); + + // Send messages + sendMessages(SPOKE, dest, MESSAGE_COUNT); + + MessageIdList msgs = getConsumerMessages(HUB, client); + msgs.setMaximumDuration(200000L); + msgs.waitForMessagesToArrive(MESSAGE_COUNT); + + assertTrue("At least message " + MESSAGE_COUNT + + " must be recieved, duplicates are expected, count=" + msgs.getMessageCount(), + MESSAGE_COUNT <= msgs.getMessageCount()); + } + + + @Override + protected void startAllBrokers() throws Exception { + // Ensure HUB is started first so bridge will be active from the get go + BrokerItem brokerItem = brokers.get(HUB); + brokerItem.broker.start(); + brokerItem = brokers.get(SPOKE); + brokerItem.broker.start(); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + final String options = "?persistent=false&useJmx=false&deleteAllMessagesOnStartup=true"; + createBroker(new URI("broker:(tcpfaulty://localhost:61617)/" + HUB + options)); + createBroker(new URI("broker:(tcpfaulty://localhost:61616)/" + SPOKE + options)); + } + + public static Test suite() { + return suite(MulticastDiscoveryOnFaultyNetworkTest.class); + } + + @Override + protected void onSend(int i, TextMessage msg) { + sleep(50); + } + + private void sleep(int milliSecondTime) { + try { + Thread.sleep(milliSecondTime); + } catch (InterruptedException igonred) { + } + } + + + @Override + protected NetworkConnector bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker, boolean dynamicOnly, int networkTTL, boolean conduit, boolean failover) throws Exception { + String networkDisoveryUrlString = useStaticDiscovery ? + "static:(" + remoteBroker.getTransportConnectors().get(0).getPublishableConnectString() + ")?useExponentialBackOff=false" : + "multicast://default?group=TESTERIC&useLocalHost=false"; + + DiscoveryNetworkConnector connector = new DiscoveryNetworkConnector(new URI(networkDisoveryUrlString)); + connector.setDynamicOnly(dynamicOnly); + connector.setNetworkTTL(networkTTL); + connector.setDuplex(useDuplexNetworkBridge); + maxSetupTime = 2000; + if (!useStaticDiscovery) { + List transportConnectors = remoteBroker.getTransportConnectors(); + if (!transportConnectors.isEmpty()) { + TransportConnector mCastTrpConnector = ((TransportConnector)transportConnectors.get(0)); + mCastTrpConnector.setDiscoveryUri(new URI("multicast://default?group=TESTERIC")); + } + } + localBroker.addNetworkConnector(connector); + return connector; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MyObject.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MyObject.java new file mode 100644 index 0000000000..d8bc5dd6c4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/MyObject.java @@ -0,0 +1,68 @@ +/** + * 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.usecases; + +import java.io.IOException; +import java.io.Serializable; +import java.util.concurrent.atomic.AtomicInteger; + +public class MyObject implements Serializable { + + private static final long serialVersionUID = -2505777188753549398L; + + private String message; + private final AtomicInteger writeObjectCalled = new AtomicInteger(0); + private final AtomicInteger readObjectCalled = new AtomicInteger(0); + private final AtomicInteger readObjectNoDataCalled = new AtomicInteger(0); + + public MyObject(String message) { + this.setMessage(message); + } + + public void setMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + writeObjectCalled.incrementAndGet(); + out.defaultWriteObject(); + } + + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + readObjectCalled.incrementAndGet(); + } + + public int getWriteObjectCalled() { + return writeObjectCalled.get(); + } + + public int getReadObjectCalled() { + return readObjectCalled.get(); + } + + public int getReadObjectNoDataCalled() { + return readObjectNoDataCalled.get(); + } +} + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkAsyncStartTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkAsyncStartTest.java new file mode 100644 index 0000000000..8f74117c2b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkAsyncStartTest.java @@ -0,0 +1,120 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.SocketProxy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetworkAsyncStartTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(NetworkAsyncStartTest.class); + + private String brokerBUri = "tcp://localhost:61617"; + private String brokerCUri = "tcp://localhost:61618"; + int bridgeCount=0; + + public void testAsyncNetworkStartup() throws Exception { + + BrokerService brokerA = brokers.get("BrokerA").broker; + bridgeBroker(brokerA, brokerBUri); + bridgeBroker(brokerA, brokerCUri); + + LOG.info("starting A, no blocking on failed network connectors"); + brokerA.start(); + + LOG.info("starting C transport connector"); + BrokerService brokerC = brokers.get("BrokerC").broker; + brokerC.addConnector(brokerCUri); + brokerC.start(); + + assertTrue("got bridge to C", waitForBridgeFormation(brokerA, 1, 1)); + LOG.info("Got bridge A->C"); + + LOG.info("starting B transport connector"); + BrokerService brokerB = brokers.get("BrokerB").broker; + brokerB.addConnector(brokerBUri); + brokerB.start(); + + assertTrue("got bridge to B", waitForBridgeFormation(brokerA, 1, 0)); + assertTrue("got bridge to B&C", waitForBridgeFormation(brokerA, 1, 1)); + } + + public void testAsyncNetworkStartupWithSlowConnectionCreation() throws Exception { + + final BrokerService brokerA = brokers.get("BrokerA").broker; + + SocketProxy proxyToB = new SocketProxy(); + // don't accept any connections so limited to one connection with backlog + proxyToB.setPauseAtStart(true); + proxyToB.setAcceptBacklog(1); + proxyToB.setTarget(new URI(brokerBUri)); + proxyToB.open(); + bridgeBroker(brokerA, proxyToB.getUrl().toString()); + bridgeBroker(brokerA, proxyToB.getUrl().toString()); + bridgeBroker(brokerA, proxyToB.getUrl().toString()); + bridgeBroker(brokerA, proxyToB.getUrl().toString()); + bridgeBroker(brokerA, proxyToB.getUrl().toString()); + bridgeBroker(brokerA, proxyToB.getUrl().toString()); + bridgeBroker(brokerA, proxyToB.getUrl().toString()); + bridgeBroker(brokerA, brokerCUri); + + Executor e = Executors.newCachedThreadPool(); + e.execute(new Runnable() { + public void run() { + LOG.info("starting A"); + try { + brokerA.setNetworkConnectorStartAsync(true); + brokerA.start(); + } catch (Exception e) { + LOG.error("start failed", e); + } + } + }); + + LOG.info("starting transport connector on C"); + BrokerService brokerC = brokers.get("BrokerC").broker; + brokerC.addConnector(brokerCUri); + brokerC.start(); + + final long maxWaitMillis = 20*1000; + assertTrue("got bridge to C in 10 seconds", waitForBridgeFormation(brokerA, 1, 7, maxWaitMillis)); + } + + private void bridgeBroker(BrokerService localBroker, String remoteURI) throws Exception { + String uri = "static:(" + remoteURI + ")"; + NetworkConnector connector = new DiscoveryNetworkConnector(new URI(uri)); + connector.setName("bridge-" + bridgeCount++); + localBroker.addNetworkConnector(connector); + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + // initially with no tcp transport connector + createBroker(new URI("broker:()BrokerA?persistent=false&useJmx=false")); + createBroker(new URI("broker:()BrokerB?persistent=false&useJmx=false")); + createBroker(new URI("broker:()BrokerC?persistent=false&useJmx=false")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkBridgeProducerFlowControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkBridgeProducerFlowControlTest.java new file mode 100644 index 0000000000..e950b7dc85 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkBridgeProducerFlowControlTest.java @@ -0,0 +1,387 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import javax.jms.MessageConsumer; +import junit.framework.Test; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.MessageIdList; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; + +/** + * This test demonstrates and verifies the behaviour of a network bridge when it + * forwards a message to a queue that is full and producer flow control is + * enabled. + *

+ * The expected behaviour is that the bridge will stop forwarding messages to + * the full queue once the associated demand consumer's prefetch is full, but + * will continue to forward messages to the other queues that are not full. + *

+ * In actuality, a message that is sent asynchronously to a local queue, + * but blocked by producer flow control on the remote queue, will stop the + * bridge from forwarding all subsequent messages, even those destined for + * remote queues that are not full. In the same scenario, but with a message + * that is sent synchronously to the local queue, the bridge continues + * forwarding messages to remote queues that are not full. + *

+ * This test demonstrates the differing behaviour via the following scenario: + *

    + *
  • broker0, designated as the local broker, produces messages to two shared + * queues + *
  • broker1, designated as the remote broker, has two consumers: the first + * consumes from one of the shared queues as fast as possible, the second + * consumes from the other shared queue with an artificial processing delay for + * each message + *
  • broker0 forwards messages to broker1 over a TCP-based network bridge + * with a demand consumer prefetch of 1 + *
  • broker1's consumers have a prefetch of 1 + *
  • broker1's "slow consumer" queue has a memory limit that triggers + * producer flow control once the queue contains a small number of messages + *
+ * In this scenario, since broker1's consumers have a prefetch of 1, the "slow + * consumer" queue will quickly become full and trigger producer flow control. + * The "fast consumer" queue is unlikely to become full. Since producer flow + * control on the "slow consumer" queue should not affect the "fast consumer" + * queue, the expectation is that the fast consumer in broker1 will finish + * processing all its messages well ahead of the slow consumer. + *

+ * The difference between expected and actual behaviour is demonstrated by + * changing the messages produced by broker0 from persistent to non-persistent. + * With persistent messages, broker0 dispatches synchronously and the expected + * behaviour is observed (i.e., the fast consumer on broker1 is much faster than + * the slow consumer). With non-persistent messages, broker0 dispatches + * asynchronously and the expected behaviour is not observed (i.e., the + * fast consumer is only marginally faster than the slow consumer). + *

+ * Since the expected behaviour may be desirable for both persistent and + * non-persistent messages, this test also demonstrates an enhancement to the + * network bridge configuration: isAlwaysSendSync. When false the + * bridge operates as originally observed. When true, the bridge + * operates with the same behaviour as was originally observed with persistent + * messages, for both persistent and non-persistent messages. + *

+ * https://issues.apache.org/jira/browse/AMQ-3331 + * + * @author schow + */ +public class NetworkBridgeProducerFlowControlTest extends + JmsMultipleBrokersTestSupport { + + // Protect against hanging test. + private static final long MAX_TEST_TIME = 120000; + + private static final Log LOG = LogFactory + .getLog(NetworkBridgeProducerFlowControlTest.class); + + // Combo flag set to true/false by the test framework. + public boolean persistentTestMessages; + public boolean networkIsAlwaysSendSync; + + private Vector exceptions = new Vector(); + + public static Test suite() { + return suite(NetworkBridgeProducerFlowControlTest.class); + } + + public void initCombosForTestFastAndSlowRemoteConsumers() { + addCombinationValues("persistentTestMessages", new Object[]{ + new Boolean(true), new Boolean(false)}); + addCombinationValues("networkIsAlwaysSendSync", new Object[]{ + new Boolean(true), new Boolean(false)}); + } + + @Override + protected void setUp() throws Exception { + setAutoFail(true); + setMaxTestTime(MAX_TEST_TIME); + super.setUp(); + } + + /** + * This test is parameterized by {@link #persistentTestMessages}, which + * determines whether the producer on broker0 sends persistent or + * non-persistent messages, and {@link #networkIsAlwaysSendSync}, which + * determines how the bridge will forward both persistent and non-persistent + * messages to broker1. + * + * @see #initCombosForTestFastAndSlowRemoteConsumers() + */ + public void testFastAndSlowRemoteConsumers() throws Exception { + final int NUM_MESSAGES = 100; + final long TEST_MESSAGE_SIZE = 1024; + final long SLOW_CONSUMER_DELAY_MILLIS = 100; + + // Consumer prefetch is disabled for broker1's consumers. + final ActiveMQQueue SLOW_SHARED_QUEUE = new ActiveMQQueue( + NetworkBridgeProducerFlowControlTest.class.getSimpleName() + + ".slow.shared?consumer.prefetchSize=1"); + + final ActiveMQQueue FAST_SHARED_QUEUE = new ActiveMQQueue( + NetworkBridgeProducerFlowControlTest.class.getSimpleName() + + ".fast.shared?consumer.prefetchSize=1"); + + // Start a local and a remote broker. + createBroker(new URI("broker:(tcp://localhost:0" + + ")?brokerName=broker0&persistent=false&useJmx=true")); + BrokerService remoteBroker = createBroker(new URI( + "broker:(tcp://localhost:0" + + ")?brokerName=broker1&persistent=false&useJmx=true")); + + // Set a policy on the remote broker that limits the maximum size of the + // slow shared queue. + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setMemoryLimit(5 * TEST_MESSAGE_SIZE); + PolicyMap policyMap = new PolicyMap(); + policyMap.put(SLOW_SHARED_QUEUE, policyEntry); + remoteBroker.setDestinationPolicy(policyMap); + + // Create an outbound bridge from the local broker to the remote broker. + // The bridge is configured with the remoteDispatchType enhancement. + NetworkConnector nc = bridgeBrokers("broker0", "broker1"); + nc.setAlwaysSyncSend(networkIsAlwaysSendSync); + nc.setPrefetchSize(1); + + startAllBrokers(); + waitForBridgeFormation(); + + // Send the test messages to the local broker's shared queues. The + // messages are either persistent or non-persistent to demonstrate the + // difference between synchronous and asynchronous dispatch. + persistentDelivery = persistentTestMessages; + sendMessages("broker0", FAST_SHARED_QUEUE, NUM_MESSAGES); + sendMessages("broker0", SLOW_SHARED_QUEUE, NUM_MESSAGES); + + // Start two asynchronous consumers on the remote broker, one for each + // of the two shared queues, and keep track of how long it takes for + // each of the consumers to receive all the messages. + final CountDownLatch fastConsumerLatch = new CountDownLatch( + NUM_MESSAGES); + final CountDownLatch slowConsumerLatch = new CountDownLatch( + NUM_MESSAGES); + + final long startTimeMillis = System.currentTimeMillis(); + final AtomicLong fastConsumerTime = new AtomicLong(); + final AtomicLong slowConsumerTime = new AtomicLong(); + + Thread fastWaitThread = new Thread() { + @Override + public void run() { + try { + fastConsumerLatch.await(); + fastConsumerTime.set(System.currentTimeMillis() + - startTimeMillis); + } catch (InterruptedException ex) { + exceptions.add(ex); + Assert.fail(ex.getMessage()); + } + } + }; + + Thread slowWaitThread = new Thread() { + @Override + public void run() { + try { + slowConsumerLatch.await(); + slowConsumerTime.set(System.currentTimeMillis() + - startTimeMillis); + } catch (InterruptedException ex) { + exceptions.add(ex); + Assert.fail(ex.getMessage()); + } + } + }; + + fastWaitThread.start(); + slowWaitThread.start(); + + createConsumer("broker1", FAST_SHARED_QUEUE, fastConsumerLatch); + MessageConsumer slowConsumer = createConsumer("broker1", + SLOW_SHARED_QUEUE, slowConsumerLatch); + MessageIdList messageIdList = brokers.get("broker1").consumers + .get(slowConsumer); + messageIdList.setProcessingDelay(SLOW_CONSUMER_DELAY_MILLIS); + + fastWaitThread.join(); + slowWaitThread.join(); + + assertTrue("no exceptions on the wait threads:" + exceptions, + exceptions.isEmpty()); + + LOG.info("Fast consumer duration (ms): " + fastConsumerTime.get()); + LOG.info("Slow consumer duration (ms): " + slowConsumerTime.get()); + + // Verify the behaviour as described in the description of this class. + if (networkIsAlwaysSendSync) { + Assert + .assertTrue(fastConsumerTime.get() < slowConsumerTime.get() / 10); + + } else { + Assert.assertEquals(persistentTestMessages, + fastConsumerTime.get() < slowConsumerTime.get() / 10); + } + } + + public void testSendFailIfNoSpaceDoesNotBlockQueueNetwork() throws Exception { + // Consumer prefetch is disabled for broker1's consumers. + final ActiveMQQueue SLOW_SHARED_QUEUE = new ActiveMQQueue( + NetworkBridgeProducerFlowControlTest.class.getSimpleName() + + ".slow.shared?consumer.prefetchSize=1"); + + final ActiveMQQueue FAST_SHARED_QUEUE = new ActiveMQQueue( + NetworkBridgeProducerFlowControlTest.class.getSimpleName() + + ".fast.shared?consumer.prefetchSize=1"); + + doTestSendFailIfNoSpaceDoesNotBlockNetwork( + SLOW_SHARED_QUEUE, + FAST_SHARED_QUEUE); + } + + public void testSendFailIfNoSpaceDoesNotBlockTopicNetwork() throws Exception { + // Consumer prefetch is disabled for broker1's consumers. + final ActiveMQTopic SLOW_SHARED_TOPIC = new ActiveMQTopic( + NetworkBridgeProducerFlowControlTest.class.getSimpleName() + + ".slow.shared?consumer.prefetchSize=1"); + + final ActiveMQTopic FAST_SHARED_TOPIC = new ActiveMQTopic( + NetworkBridgeProducerFlowControlTest.class.getSimpleName() + + ".fast.shared?consumer.prefetchSize=1"); + + doTestSendFailIfNoSpaceDoesNotBlockNetwork( + SLOW_SHARED_TOPIC, + FAST_SHARED_TOPIC); + } + + public void doTestSendFailIfNoSpaceDoesNotBlockNetwork( + ActiveMQDestination slowDestination, ActiveMQDestination fastDestination) throws Exception { + + final int NUM_MESSAGES = 100; + final long TEST_MESSAGE_SIZE = 1024; + final long SLOW_CONSUMER_DELAY_MILLIS = 100; + + // Start a local and a remote broker. + createBroker(new URI("broker:(tcp://localhost:0" + + ")?brokerName=broker0&persistent=false&useJmx=true")); + BrokerService remoteBroker = createBroker(new URI( + "broker:(tcp://localhost:0" + + ")?brokerName=broker1&persistent=false&useJmx=true")); + remoteBroker.getSystemUsage().setSendFailIfNoSpace(true); + + // Set a policy on the remote broker that limits the maximum size of the + // slow shared queue. + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setMemoryLimit(5 * TEST_MESSAGE_SIZE); + PolicyMap policyMap = new PolicyMap(); + policyMap.put(slowDestination, policyEntry); + remoteBroker.setDestinationPolicy(policyMap); + + // Create an outbound bridge from the local broker to the remote broker. + // The bridge is configured with the remoteDispatchType enhancement. + NetworkConnector nc = bridgeBrokers("broker0", "broker1"); + nc.setAlwaysSyncSend(true); + nc.setPrefetchSize(1); + + startAllBrokers(); + waitForBridgeFormation(); + + // Start two asynchronous consumers on the remote broker, one for each + // of the two shared queues, and keep track of how long it takes for + // each of the consumers to receive all the messages. + final CountDownLatch fastConsumerLatch = new CountDownLatch( + NUM_MESSAGES); + final CountDownLatch slowConsumerLatch = new CountDownLatch( + NUM_MESSAGES); + + final long startTimeMillis = System.currentTimeMillis(); + final AtomicLong fastConsumerTime = new AtomicLong(); + final AtomicLong slowConsumerTime = new AtomicLong(); + + Thread fastWaitThread = new Thread() { + @Override + public void run() { + try { + fastConsumerLatch.await(); + fastConsumerTime.set(System.currentTimeMillis() + - startTimeMillis); + } catch (InterruptedException ex) { + exceptions.add(ex); + Assert.fail(ex.getMessage()); + } + } + }; + + Thread slowWaitThread = new Thread() { + @Override + public void run() { + try { + slowConsumerLatch.await(); + slowConsumerTime.set(System.currentTimeMillis() + - startTimeMillis); + } catch (InterruptedException ex) { + exceptions.add(ex); + Assert.fail(ex.getMessage()); + } + } + }; + + fastWaitThread.start(); + slowWaitThread.start(); + + createConsumer("broker1", fastDestination, fastConsumerLatch); + MessageConsumer slowConsumer = createConsumer("broker1", + slowDestination, slowConsumerLatch); + MessageIdList messageIdList = brokers.get("broker1").consumers + .get(slowConsumer); + messageIdList.setProcessingDelay(SLOW_CONSUMER_DELAY_MILLIS); + + // Send the test messages to the local broker's shared queues. The + // messages are either persistent or non-persistent to demonstrate the + // difference between synchronous and asynchronous dispatch. + persistentDelivery = false; + sendMessages("broker0", fastDestination, NUM_MESSAGES); + sendMessages("broker0", slowDestination, NUM_MESSAGES); + + fastWaitThread.join(TimeUnit.SECONDS.toMillis(60)); + slowWaitThread.join(TimeUnit.SECONDS.toMillis(60)); + + assertTrue("no exceptions on the wait threads:" + exceptions, + exceptions.isEmpty()); + + LOG.info("Fast consumer duration (ms): " + fastConsumerTime.get()); + LOG.info("Slow consumer duration (ms): " + slowConsumerTime.get()); + + assertTrue("fast time set", fastConsumerTime.get() > 0); + assertTrue("slow time set", slowConsumerTime.get() > 0); + + // Verify the behaviour as described in the description of this class. + Assert.assertTrue(fastConsumerTime.get() < slowConsumerTime.get() / 10); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkOfTwentyBrokersTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkOfTwentyBrokersTest.java new file mode 100644 index 0000000000..f1266e3f33 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NetworkOfTwentyBrokersTest.java @@ -0,0 +1,217 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.ThreadTracker; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetworkOfTwentyBrokersTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(NetworkOfTwentyBrokersTest.class); + + // This will interconnect all brokers using multicast + protected void bridgeAllBrokers() throws Exception { + bridgeAllBrokers("TwentyBrokersTest", 1, false, false); + } + + protected void bridgeAllBrokers(String groupName, int ttl, boolean suppressduplicateQueueSubs) throws Exception { + bridgeAllBrokers(groupName, ttl, suppressduplicateQueueSubs, false); + } + + protected void bridgeAllBrokers(String groupName, int ttl, boolean suppressduplicateQueueSubs, boolean decreasePriority) throws Exception { + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + List transportConnectors = broker.getTransportConnectors(); + + if (transportConnectors.isEmpty()) { + broker.addConnector(new URI(AUTO_ASSIGN_TRANSPORT)); + transportConnectors = broker.getTransportConnectors(); + } + + TransportConnector transport = transportConnectors.get(0); + if (transport.getDiscoveryUri() == null) { + transport.setDiscoveryUri(new URI("multicast://default?group=" + groupName)); + } + + List networkConnectors = broker.getNetworkConnectors(); + if (networkConnectors.isEmpty()) { + broker.addNetworkConnector("multicast://default?group=" + groupName); + networkConnectors = broker.getNetworkConnectors(); + } + + NetworkConnector nc = networkConnectors.get(0); + nc.setNetworkTTL(ttl); + nc.setSuppressDuplicateQueueSubscriptions(suppressduplicateQueueSubs); + nc.setDecreaseNetworkConsumerPriority(decreasePriority); + } + + // Multicasting may take longer to setup + maxSetupTime = 8000; + } + + protected BrokerService createBroker(String brokerName) throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.setBrokerName(brokerName); + broker.addConnector(new URI(AUTO_ASSIGN_TRANSPORT)); + brokers.put(brokerName, new BrokerItem(broker)); + + return broker; + } + + /* AMQ-3077 Bug */ + public void testBrokers() throws Exception { + int X = 20; + int i; + + LOG.info("Creating X Brokers"); + for (i = 0; i < X; i++) { + createBroker("Broker" + i); + } + + bridgeAllBrokers(); + startAllBrokers(); + waitForBridgeFormation(X-1); + + LOG.info("Waiting for complete formation"); + try { + Thread.sleep(20000); + } catch (Exception e) { + } + + verifyPeerBrokerInfos(X-1); + + LOG.info("Stopping half the brokers"); + for (i = 0; i < X/2; i++) { + destroyBroker("Broker" + i); + } + + LOG.info("Waiting for complete stop"); + try { + Thread.sleep(20000); + } catch (Exception e) { + } + + verifyPeerBrokerInfos((X/2) - 1); + + LOG.info("Recreating first half"); + for (i = 0; i < X/2; i++) { + createBroker("Broker" + i); + } + + bridgeAllBrokers(); + startAllBrokers(); + waitForBridgeFormation(X-1); + + LOG.info("Waiting for complete reformation"); + try { + Thread.sleep(20000); + } catch (Exception e) { + } + + verifyPeerBrokerInfos(X-1); + } + + public void testPeerBrokerCountHalfPeer() throws Exception { + createBroker("A"); + createBroker("B"); + bridgeBrokers("A", "B"); + startAllBrokers(); + verifyPeerBrokerInfo(brokers.get("A"), 1); + verifyPeerBrokerInfo(brokers.get("B"), 0); + } + + public void testPeerBrokerCountHalfPeerTwice() throws Exception { + createBroker("A"); + createBroker("B"); + bridgeBrokers("A", "B"); + bridgeBrokers("A", "B"); + startAllBrokers(); + verifyPeerBrokerInfo(brokers.get("A"), 1); + verifyPeerBrokerInfo(brokers.get("B"), 0); + } + + public void testPeerBrokerCountFullPeer() throws Exception { + createBroker("A"); + createBroker("B"); + bridgeBrokers("A", "B"); + bridgeBrokers("B", "A"); + startAllBrokers(); + verifyPeerBrokerInfo(brokers.get("A"), 1); + verifyPeerBrokerInfo(brokers.get("B"), 1); + } + + public void testPeerBrokerCountFullPeerDuplex() throws Exception { + createBroker("A"); + createBroker("B"); + NetworkConnector nc = bridgeBrokers("A", "B"); + nc.setDuplex(true); + startAllBrokers(); + verifyPeerBrokerInfo(brokers.get("A"), 1); + verifyPeerBrokerInfo(brokers.get("B"), 1); + } + + + private void verifyPeerBrokerInfo(BrokerItem brokerItem, final int max) throws Exception { + final BrokerService broker = brokerItem.broker; + final RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("verify infos " + broker.getBrokerName() + ", len: " + regionBroker.getPeerBrokerInfos().length); + return max == regionBroker.getPeerBrokerInfos().length; + } + }, 120 * 1000); + LOG.info("verify infos " + broker.getBrokerName() + ", len: " + regionBroker.getPeerBrokerInfos().length); + for (BrokerInfo info : regionBroker.getPeerBrokerInfos()) { + LOG.info(info.getBrokerName()); + } + assertEquals(broker.getBrokerName(), max, regionBroker.getPeerBrokerInfos().length); + } + + private void verifyPeerBrokerInfos(final int max) throws Exception { + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + verifyPeerBrokerInfo(i.next(), max); + } + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + ThreadTracker.result(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NewConsumerCreatesDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NewConsumerCreatesDestinationTest.java new file mode 100644 index 0000000000..30ae2ec188 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NewConsumerCreatesDestinationTest.java @@ -0,0 +1,63 @@ +/** + * 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.usecases; + +import java.util.Set; + +import javax.jms.Destination; +import javax.jms.Session; + +import org.apache.activemq.EmbeddedBrokerAndConnectionTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class NewConsumerCreatesDestinationTest extends EmbeddedBrokerAndConnectionTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(NewConsumerCreatesDestinationTest.class); + + private ActiveMQQueue wildcard; + + public void testNewConsumerCausesNewDestinationToBeAutoCreated() throws Exception { + + // lets create a wildcard thats kinda like those used by Virtual Topics + String wildcardText = "org.*" + getDestinationString().substring("org.apache".length()); + wildcard = new ActiveMQQueue(wildcardText); + + LOG.info("Using wildcard: " + wildcard); + LOG.info("on destination: " + destination); + + assertDestinationCreated(destination, false); + assertDestinationCreated(wildcard, false); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + session.createConsumer(destination); + + assertDestinationCreated(destination, true); + assertDestinationCreated(wildcard, true); + } + + protected void assertDestinationCreated(Destination destination, boolean expected) throws Exception { + Set answer = broker.getBroker().getDestinations((ActiveMQDestination) destination); + int size = expected ? 1 : 0; + assertEquals("Size of found destinations: " + answer, size, answer.size()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NoDuplicateOnTopicNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NoDuplicateOnTopicNetworkTest.java new file mode 100644 index 0000000000..2aa614d9c1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NoDuplicateOnTopicNetworkTest.java @@ -0,0 +1,374 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.Subscription; +import org.apache.activemq.broker.region.policy.DispatchPolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.PriorityNetworkDispatchPolicy; +import org.apache.activemq.broker.region.policy.SimpleDispatchPolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NoDuplicateOnTopicNetworkTest extends CombinationTestSupport { + private static final Logger LOG = LoggerFactory + .getLogger(NoDuplicateOnTopicNetworkTest.class); + + private static final String MULTICAST_DEFAULT = "multicast://default"; + private static final String BROKER_1 = "tcp://localhost:61626"; + private static final String BROKER_2 = "tcp://localhost:61636"; + private static final String BROKER_3 = "tcp://localhost:61646"; + private final static String TOPIC_NAME = "broadcast"; + private static byte BASE_PRIORITY = -20; + private BrokerService broker1; + private BrokerService broker2; + private BrokerService broker3; + + public boolean suppressDuplicateTopicSubs = false; + public DispatchPolicy dispatchPolicy = new SimpleDispatchPolicy(); + public boolean durableSub = false; + AtomicInteger idCounter = new AtomicInteger(0); + + private boolean dynamicOnly = false; + // no duplicates in cyclic network if networkTTL <=1 + // when > 1, subscriptions percolate around resulting in duplicates as there is no + // memory of the original subscription. + // solution for 6.0 using org.apache.activemq.command.ConsumerInfo.getNetworkConsumerIds() + private int ttl = 3; + + + + @Override + protected void setUp() throws Exception { + super.setUp(); + + broker3 = createAndStartBroker("broker3", BROKER_3); + Thread.sleep(3000); + broker2 = createAndStartBroker("broker2", BROKER_2); + Thread.sleep(3000); + broker1 = createAndStartBroker("broker1", BROKER_1); + Thread.sleep(1000); + + waitForBridgeFormation(); + } + + public static Test suite() { + return suite(NoDuplicateOnTopicNetworkTest.class); + } + + protected void waitForBridgeFormation() throws Exception { + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return !broker3.getNetworkConnectors().get(0).activeBridges().isEmpty(); + }}); + + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return !broker2.getNetworkConnectors().get(0).activeBridges().isEmpty(); + }}); + + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return !broker1.getNetworkConnectors().get(0).activeBridges().isEmpty(); + }}); + } + + private BrokerService createAndStartBroker(String name, String addr) + throws Exception { + BrokerService broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setBrokerName(name); + broker.addConnector(addr).setDiscoveryUri(new URI(MULTICAST_DEFAULT)); + broker.setUseJmx(false); + + NetworkConnector networkConnector = broker + .addNetworkConnector(MULTICAST_DEFAULT); + networkConnector.setDecreaseNetworkConsumerPriority(true); + networkConnector.setDynamicOnly(dynamicOnly); + networkConnector.setNetworkTTL(ttl); + networkConnector.setSuppressDuplicateTopicSubscriptions(suppressDuplicateTopicSubs); + networkConnector.setConsumerPriorityBase(BASE_PRIORITY); + networkConnector.addStaticallyIncludedDestination(new ActiveMQTopic("BeStaticallyIncluded")); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policy = new PolicyEntry(); + policy.setDispatchPolicy(dispatchPolicy); + // the audit will suppress the duplicates as it defaults to true so this test + // checking for dups will fail. it is good to have it on in practice. + policy.setEnableAudit(false); + policyMap.put(new ActiveMQTopic(TOPIC_NAME), policy); + broker.setDestinationPolicy(policyMap); + broker.start(); + + return broker; + } + + @Override + protected void tearDown() throws Exception { + broker1.stop(); + broker2.stop(); + broker3.stop(); + super.tearDown(); + } + + public void initCombosForTestProducerConsumerTopic() { + this.addCombinationValues("suppressDuplicateTopicSubs", new Object[]{Boolean.TRUE, Boolean.FALSE}); + this.addCombinationValues("dispatchPolicy", new Object[]{new PriorityNetworkDispatchPolicy(), new SimpleDispatchPolicy()}); + this.addCombinationValues("durableSub", new Object[]{Boolean.TRUE, Boolean.FALSE}); + } + + public void testProducerConsumerTopic() throws Exception { + + final CountDownLatch consumerStarted = new CountDownLatch(1); + + Thread producerThread = new Thread(new Runnable() { + public void run() { + TopicWithDuplicateMessages producer = new TopicWithDuplicateMessages(); + producer.setBrokerURL(BROKER_1); + producer.setTopicName(TOPIC_NAME); + try { + producer.produce(); + } catch (JMSException e) { + fail("Unexpected " + e); + } + } + }); + + final TopicWithDuplicateMessages consumer = new TopicWithDuplicateMessages(); + Thread consumerThread = new Thread(new Runnable() { + public void run() { + consumer.setBrokerURL(BROKER_2); + consumer.setTopicName(TOPIC_NAME); + try { + consumer.consumer(); + consumerStarted.countDown(); + consumer.getLatch().await(60, TimeUnit.SECONDS); + } catch (Exception e) { + fail("Unexpected " + e); + } + } + }); + + consumerThread.start(); + LOG.info("Started Consumer"); + + assertTrue("consumer started eventually", consumerStarted.await(10, TimeUnit.SECONDS)); + + // ensure subscription has percolated though the network + Thread.sleep(2000); + + // verify network consumer priority + final RegionBroker regionBroker = (RegionBroker)broker1.getRegionBroker(); + assertTrue("Found network destination with priority as expected", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + Map destinationMap = regionBroker.getTopicRegion().getDestinationMap(); + LOG.info("destinations: " + destinationMap.keySet()); + boolean found = false; + for (Destination destination : destinationMap.values()) { + List subscriptions = destination.getConsumers(); + LOG.info(destination + " subscriptions: " + subscriptions); + for (Subscription subscription : subscriptions) { + if (subscription.getConsumerInfo().isNetworkSubscription()) { + LOG.info("subscription: " + subscription + ", priority: " + subscription.getConsumerInfo().getPriority()); + assertTrue("priority is < our base: " + subscription.getConsumerInfo().getPriority(), + subscription.getConsumerInfo().getPriority() <= BASE_PRIORITY); + found = true; + } + } + } + return found; + } + })); + + producerThread.start(); + LOG.info("Started Producer"); + producerThread.join(); + consumerThread.join(); + + int duplicateCount = 0; + Map map = new HashMap(); + for (String msg : consumer.getMessageStrings()) { + if (map.containsKey(msg)) { + LOG.info("got duplicate: " + msg); + duplicateCount++; + } + map.put(msg, msg); + } + consumer.unSubscribe(); + if (suppressDuplicateTopicSubs || dispatchPolicy instanceof PriorityNetworkDispatchPolicy) { + assertEquals("no duplicates", 0, duplicateCount); + assertEquals("got all required messages: " + map.size(), consumer + .getNumMessages(), map.size()); + } else { + assertTrue("we can get some duplicates: " + duplicateCount, duplicateCount >= 0); + if (duplicateCount == 0) { + assertEquals("got all required messages: " + map.size(), consumer + .getNumMessages(), map.size()); + } + } + } + + class TopicWithDuplicateMessages { + private String brokerURL; + private String topicName; + private Connection connection; + private Session session; + private Topic topic; + private MessageProducer producer; + private MessageConsumer consumer; + private final String durableID = "DURABLE_ID"; + + private List receivedStrings = Collections.synchronizedList(new ArrayList()); + private int numMessages = 10; + private CountDownLatch recievedLatch = new CountDownLatch(numMessages); + + public CountDownLatch getLatch() { + return recievedLatch; + } + + public List getMessageStrings() { + synchronized(receivedStrings) { + return new ArrayList(receivedStrings); + } + } + + public String getBrokerURL() { + return brokerURL; + } + + public void setBrokerURL(String brokerURL) { + this.brokerURL = brokerURL; + } + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + private void createConnection() throws JMSException { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + brokerURL); + connection = factory.createConnection(); + connection.setClientID("ID" + idCounter.incrementAndGet()); + } + + private void createTopic() throws JMSException { + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = session.createTopic(topicName); + } + + private void createProducer() throws JMSException { + producer = session.createProducer(topic); + } + + private void createConsumer() throws JMSException { + if (durableSub) { + consumer = session.createDurableSubscriber(topic, durableID); + } else { + consumer = session.createConsumer(topic); + } + consumer.setMessageListener(new MessageListener() { + + public void onMessage(Message arg0) { + TextMessage msg = (TextMessage) arg0; + try { + LOG.debug("Received message [" + msg.getText() + "]"); + receivedStrings.add(msg.getText()); + recievedLatch.countDown(); + } catch (JMSException e) { + fail("Unexpected :" + e); + } + } + + }); + } + + private void publish() throws JMSException { + for (int i = 0; i < numMessages; i++) { + TextMessage textMessage = session.createTextMessage(); + String message = "message: " + i; + LOG.debug("Sending message[" + message + "]"); + textMessage.setText(message); + producer.send(textMessage); + } + } + + public void produce() throws JMSException { + createConnection(); + createTopic(); + createProducer(); + connection.start(); + publish(); + } + + public void consumer() throws JMSException { + createConnection(); + createTopic(); + createConsumer(); + connection.start(); + } + + public int getNumMessages() { + return numMessages; + } + + public void unSubscribe() throws Exception { + consumer.close(); + if (durableSub) { + session.unsubscribe(durableID); + // ensure un-subscription has percolated though the network + Thread.sleep(2000); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NonBlockingConsumerRedeliveryTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NonBlockingConsumerRedeliveryTest.java new file mode 100644 index 0000000000..aa829d5f59 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/NonBlockingConsumerRedeliveryTest.java @@ -0,0 +1,465 @@ +/** + * 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.usecases; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.RedeliveryPolicy; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NonBlockingConsumerRedeliveryTest { + private static final Logger LOG = LoggerFactory.getLogger(NonBlockingConsumerRedeliveryTest.class); + + private final String destinationName = "Destination"; + private final int MSG_COUNT = 100; + + private BrokerService broker; + private String connectionUri; + + private ActiveMQConnectionFactory connectionFactory; + + @Test + public void testMessageDeleiveredWhenNonBlockingEnabled() throws Exception { + + final LinkedHashSet received = new LinkedHashSet(); + final LinkedHashSet beforeRollback = new LinkedHashSet(); + final LinkedHashSet afterRollback = new LinkedHashSet(); + + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageConsumer consumer = session.createConsumer(destination); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received.add(message); + } + }); + + sendMessages(); + + session.commit(); + connection.start(); + + assertTrue("Pre-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages."); + return received.size() == MSG_COUNT; + } + } + )); + + beforeRollback.addAll(received); + received.clear(); + session.rollback(); + + assertTrue("Post-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages since rollback."); + return received.size() == MSG_COUNT; + } + } + )); + + afterRollback.addAll(received); + received.clear(); + + assertEquals(beforeRollback.size(), afterRollback.size()); + assertEquals(beforeRollback, afterRollback); + session.commit(); + } + + @Test + public void testMessageDeleiveredInCorrectOrder() throws Exception { + + final LinkedHashSet received = new LinkedHashSet(); + final LinkedHashSet beforeRollback = new LinkedHashSet(); + final LinkedHashSet afterRollback = new LinkedHashSet(); + + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageConsumer consumer = session.createConsumer(destination); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received.add(message); + } + }); + + sendMessages(); + + session.commit(); + connection.start(); + + assertTrue("Pre-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages."); + return received.size() == MSG_COUNT; + } + } + )); + + beforeRollback.addAll(received); + received.clear(); + session.rollback(); + + assertTrue("Post-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages since rollback."); + return received.size() == MSG_COUNT; + } + } + )); + + afterRollback.addAll(received); + received.clear(); + + assertEquals(beforeRollback.size(), afterRollback.size()); + assertEquals(beforeRollback, afterRollback); + + Iterator after = afterRollback.iterator(); + Iterator before = beforeRollback.iterator(); + + while (before.hasNext() && after.hasNext()) { + TextMessage original = (TextMessage) before.next(); + TextMessage rolledBack = (TextMessage) after.next(); + + int originalInt = Integer.parseInt(original.getText()); + int rolledbackInt = Integer.parseInt(rolledBack.getText()); + + assertEquals(originalInt, rolledbackInt); + } + + session.commit(); + } + + @Test + public void testMessageDeleiveryDoesntStop() throws Exception { + + final LinkedHashSet received = new LinkedHashSet(); + final LinkedHashSet beforeRollback = new LinkedHashSet(); + final LinkedHashSet afterRollback = new LinkedHashSet(); + + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageConsumer consumer = session.createConsumer(destination); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received.add(message); + } + }); + + sendMessages(); + connection.start(); + + assertTrue("Pre-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages."); + return received.size() == MSG_COUNT; + } + } + )); + + beforeRollback.addAll(received); + received.clear(); + session.rollback(); + + sendMessages(); + + assertTrue("Post-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages since rollback."); + return received.size() == MSG_COUNT * 2; + } + } + )); + + afterRollback.addAll(received); + received.clear(); + + assertEquals(beforeRollback.size() * 2, afterRollback.size()); + + session.commit(); + } + + @Test + public void testNonBlockingMessageDeleiveryIsDelayed() throws Exception { + final LinkedHashSet received = new LinkedHashSet(); + + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.getRedeliveryPolicy().setInitialRedeliveryDelay(TimeUnit.SECONDS.toMillis(6)); + Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageConsumer consumer = session.createConsumer(destination); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received.add(message); + } + }); + + sendMessages(); + connection.start(); + + assertTrue("Pre-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages."); + return received.size() == MSG_COUNT; + } + } + )); + + received.clear(); + session.rollback(); + + assertFalse("Delayed redelivery test not expecting any messages yet.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + return received.size() > 0; + } + }, TimeUnit.SECONDS.toMillis(4) + )); + + session.commit(); + session.close(); + } + + @Test + public void testNonBlockingMessageDeleiveryWithRollbacks() throws Exception { + final LinkedHashSet received = new LinkedHashSet(); + + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + final Destination destination = session.createQueue(destinationName); + final MessageConsumer consumer = session.createConsumer(destination); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received.add(message); + } + }); + + sendMessages(); + connection.start(); + + assertTrue("Pre-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages."); + return received.size() == MSG_COUNT; + } + } + )); + + received.clear(); + + consumer.setMessageListener(new MessageListener() { + + int count = 0; + + @Override + public void onMessage(Message message) { + + if (++count > 10) { + try { + session.rollback(); + LOG.info("Rolling back session."); + count = 0; + } catch (JMSException e) { + LOG.warn("Caught an unexcepted exception: " + e.getMessage()); + } + } else { + received.add(message); + try { + session.commit(); + } catch (JMSException e) { + LOG.warn("Caught an unexcepted exception: " + e.getMessage()); + } + } + } + }); + + session.rollback(); + + assertTrue("Post-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages since rollback."); + return received.size() == MSG_COUNT; + } + } + )); + + assertEquals(MSG_COUNT, received.size()); + session.commit(); + } + + @Test + public void testNonBlockingMessageDeleiveryWithAllRolledBack() throws Exception { + final LinkedHashSet received = new LinkedHashSet(); + final LinkedHashSet dlqed = new LinkedHashSet(); + + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.getRedeliveryPolicy().setMaximumRedeliveries(5); + final Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + final Destination destination = session.createQueue(destinationName); + final Destination dlq = session.createQueue("ActiveMQ.DLQ"); + final MessageConsumer consumer = session.createConsumer(destination); + final MessageConsumer dlqConsumer = session.createConsumer(dlq); + + dlqConsumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + dlqed.add(message); + } + }); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + received.add(message); + } + }); + + sendMessages(); + connection.start(); + + assertTrue("Pre-Rollback expects to receive: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + received.size() + " messages."); + return received.size() == MSG_COUNT; + } + } + )); + + session.rollback(); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + session.rollback(); + } catch (JMSException e) { + LOG.warn("Caught an unexcepted exception: " + e.getMessage()); + } + } + }); + + assertTrue("Post-Rollback expects to DLQ: " + MSG_COUNT + " messages.", + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + LOG.info("Consumer has received " + dlqed.size() + " messages in DLQ."); + return dlqed.size() == MSG_COUNT; + } + } + )); + + session.commit(); + } + + private void sendMessages() throws Exception { + Connection connection = connectionFactory.createConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(destinationName); + MessageProducer producer = session.createProducer(destination); + for(int i = 0; i < MSG_COUNT; ++i) { + producer.send(session.createTextMessage("" + i)); + } + } + + @Before + public void startBroker() throws Exception { + broker = new BrokerService(); + broker.setDeleteAllMessagesOnStartup(true); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://0.0.0.0:0"); + broker.start(); + broker.waitUntilStarted(); + + connectionUri = broker.getTransportConnectors().get(0).getPublishableConnectString(); + connectionFactory = new ActiveMQConnectionFactory(connectionUri); + connectionFactory.setNonBlockingRedelivery(true); + + RedeliveryPolicy policy = connectionFactory.getRedeliveryPolicy(); + policy.setInitialRedeliveryDelay(TimeUnit.SECONDS.toMillis(2)); + policy.setBackOffMultiplier(-1); + policy.setRedeliveryDelay(TimeUnit.SECONDS.toMillis(2)); + policy.setMaximumRedeliveryDelay(-1); + policy.setUseExponentialBackOff(false); + policy.setMaximumRedeliveries(-1); + } + + @After + public void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ObjectMessageNotSerializableTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ObjectMessageNotSerializableTest.java new file mode 100644 index 0000000000..c9f0f5306a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ObjectMessageNotSerializableTest.java @@ -0,0 +1,273 @@ +/** + * 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.usecases; + +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQObjectMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class ObjectMessageNotSerializableTest extends CombinationTestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(ObjectMessageNotSerializableTest.class); + + BrokerService broker; + AtomicInteger numReceived = new AtomicInteger(0); + final Vector exceptions = new Vector(); + + public static Test suite() { + return suite(ObjectMessageNotSerializableTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + protected void setUp() throws Exception { + exceptions.clear(); + broker = createBroker(); + } + + public void testSendNotSerializeableObjectMessage() throws Exception { + + final ActiveMQDestination destination = new ActiveMQQueue("testQ"); + final MyObject obj = new MyObject("A message"); + + final CountDownLatch consumerStarted = new CountDownLatch(1); + + Thread vmConsumerThread = new Thread("Consumer Thread") { + public void run() { + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setOptimizedMessageDispatch(true); + factory.setObjectMessageSerializationDefered(true); + factory.setCopyMessageOnSend(false); + + Connection connection = factory.createConnection(); + Session session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + consumerStarted.countDown(); + ActiveMQObjectMessage message = (ActiveMQObjectMessage)consumer.receive(30000); + if ( message != null ) { + MyObject object = (MyObject)message.getObject(); + LOG.info("Got message " + object.getMessage()); + numReceived.incrementAndGet(); + } + consumer.close(); + } catch (Throwable ex) { + exceptions.add(ex); + } + } + }; + vmConsumerThread.start(); + + Thread producingThread = new Thread("Producing Thread") { + public void run() { + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setOptimizedMessageDispatch(true); + factory.setObjectMessageSerializationDefered(true); + factory.setCopyMessageOnSend(false); + + Connection connection = factory.createConnection(); + Session session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + ActiveMQObjectMessage message = (ActiveMQObjectMessage)session.createObjectMessage(); + message.setObject(obj); + producer.send(message); + producer.close(); + } catch (Throwable ex) { + exceptions.add(ex); + } + } + }; + + assertTrue("consumers started", consumerStarted.await(10, TimeUnit.SECONDS)); + producingThread.start(); + + vmConsumerThread.join(); + producingThread.join(); + + assertEquals("writeObject called", 0, obj.getWriteObjectCalled()); + assertEquals("readObject called", 0, obj.getReadObjectCalled()); + assertEquals("readObjectNoData called", 0, obj.getReadObjectNoDataCalled()); + + assertEquals("Got expected messages", 1, numReceived.get()); + assertTrue("no unexpected exceptions: " + exceptions, exceptions.isEmpty()); + } + + public void testSendNotSerializeableObjectMessageOverTcp() throws Exception { + final ActiveMQDestination destination = new ActiveMQTopic("testTopic"); + final MyObject obj = new MyObject("A message"); + + final CountDownLatch consumerStarted = new CountDownLatch(3); + final Vector exceptions = new Vector(); + Thread vmConsumerThread = new Thread("Consumer Thread") { + public void run() { + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setOptimizedMessageDispatch(true); + factory.setObjectMessageSerializationDefered(true); + factory.setCopyMessageOnSend(false); + + Connection connection = factory.createConnection(); + Session session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + consumerStarted.countDown(); + ActiveMQObjectMessage message = (ActiveMQObjectMessage)consumer.receive(30000); + if ( message != null ) { + MyObject object = (MyObject)message.getObject(); + LOG.info("Got message " + object.getMessage()); + numReceived.incrementAndGet(); + } + consumer.close(); + } catch (Throwable ex) { + exceptions.add(ex); + } + } + }; + vmConsumerThread.start(); + + Thread tcpConsumerThread = new Thread("Consumer Thread") { + public void run() { + try { + + ActiveMQConnectionFactory factory = + new ActiveMQConnectionFactory(broker.getTransportConnectors().get(0).getConnectUri()); + factory.setOptimizedMessageDispatch(true); + + Connection connection = factory.createConnection(); + Session session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + consumerStarted.countDown(); + ActiveMQObjectMessage message = (ActiveMQObjectMessage)consumer.receive(30000); + if ( message != null ) { + MyObject object = (MyObject)message.getObject(); + LOG.info("Got message " + object.getMessage()); + numReceived.incrementAndGet(); + assertEquals("readObject called", 1, object.getReadObjectCalled()); + } + consumer.close(); + } catch (Throwable ex) { + exceptions.add(ex); + } + } + }; + tcpConsumerThread.start(); + + + Thread notherVmConsumerThread = new Thread("Consumer Thread") { + public void run() { + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setOptimizedMessageDispatch(true); + factory.setObjectMessageSerializationDefered(true); + factory.setCopyMessageOnSend(false); + + Connection connection = factory.createConnection(); + Session session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + consumerStarted.countDown(); + ActiveMQObjectMessage message = (ActiveMQObjectMessage)consumer.receive(30000); + if ( message != null ) { + MyObject object = (MyObject)message.getObject(); + LOG.info("Got message " + object.getMessage()); + numReceived.incrementAndGet(); + } + consumer.close(); + } catch (Throwable ex) { + exceptions.add(ex); + } + } + }; + notherVmConsumerThread.start(); + + Thread producingThread = new Thread("Producing Thread") { + public void run() { + try { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + factory.setOptimizedMessageDispatch(true); + factory.setObjectMessageSerializationDefered(true); + factory.setCopyMessageOnSend(false); + + Connection connection = factory.createConnection(); + Session session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(destination); + ActiveMQObjectMessage message = (ActiveMQObjectMessage)session.createObjectMessage(); + message.setObject(obj); + producer.send(message); + producer.close(); + } catch (Throwable ex) { + exceptions.add(ex); + } + } + }; + + assertTrue("consumers started", consumerStarted.await(10, TimeUnit.SECONDS)); + producingThread.start(); + + vmConsumerThread.join(); + tcpConsumerThread.join(); + notherVmConsumerThread.join(); + producingThread.join(); + + assertEquals("writeObject called", 1, obj.getWriteObjectCalled()); + assertEquals("readObject called", 0, obj.getReadObjectCalled()); + assertEquals("readObjectNoData called", 0, obj.getReadObjectNoDataCalled()); + + assertEquals("Got expected messages", 3, numReceived.get()); + assertTrue("no unexpected exceptions: " + exceptions, exceptions.isEmpty()); + } + + private BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.addConnector("tcp://localhost:0"); + + broker.start(); + broker.waitUntilStarted(); + return broker; + } + + protected void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ProducerConsumerTestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ProducerConsumerTestSupport.java new file mode 100644 index 0000000000..ce0c135f64 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ProducerConsumerTestSupport.java @@ -0,0 +1,56 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + + +/** + * Base class for simple test cases using a single connection, session + * producer and consumer + * + * + */ +public class ProducerConsumerTestSupport extends TestSupport { + protected Connection connection; + protected Session session; + protected MessageProducer producer; + protected MessageConsumer consumer; + protected Destination destination; + + protected void setUp() throws Exception { + super.setUp(); + connection = createConnection(); + session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = this.createDestination(getSubject()); + producer = session.createProducer(destination); + consumer = session.createConsumer(destination); + connection.start(); + } + + protected void tearDown() throws Exception { + consumer.close(); + producer.close(); + session.close(); + connection.close(); + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnDurableTopicConsumedMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnDurableTopicConsumedMessageTest.java new file mode 100644 index 0000000000..c701301a3e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnDurableTopicConsumedMessageTest.java @@ -0,0 +1,28 @@ +/** + * 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.usecases; + +/** + * + */ +public class PublishOnDurableTopicConsumedMessageTest extends PublishOnTopicConsumedMessageTest { + + protected void setUp() throws Exception { + this.durable = true; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageInTransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageInTransactionTest.java new file mode 100644 index 0000000000..ae203b0471 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageInTransactionTest.java @@ -0,0 +1,186 @@ +/** + * 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.usecases; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Session; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.IOHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class PublishOnQueueConsumedMessageInTransactionTest extends TestCase implements MessageListener { + + private static final Logger LOG = LoggerFactory.getLogger(PublishOnQueueConsumedMessageInTransactionTest.class); + + private Session producerSession; + private Session consumerSession; + private Destination queue; + private ActiveMQConnectionFactory factory; + private MessageProducer producer; + private MessageConsumer consumer; + private Connection connection; + private ObjectMessage objectMessage; + private List messages = createConcurrentList(); + private final Object lock = new Object(); + private String[] data; + private String dataFileRoot = IOHelper.getDefaultDataDirectory(); + private int messageCount = 3; + private String url = "vm://localhost"; + + // Invalid acknowledgment warning can be viewed on the console of a remote + // broker + // The warning message is not thrown back to the client + // private String url = "tcp://localhost:61616"; + + protected void setUp() throws Exception { + File dataFile = new File(dataFileRoot); + recursiveDelete(dataFile); + try { + factory = new ActiveMQConnectionFactory(url); + connection = factory.createConnection(); + producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + consumerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + queue = new ActiveMQQueue("FOO.BAR"); + data = new String[messageCount]; + + for (int i = 0; i < messageCount; i++) { + data[i] = "Message : " + i; + } + } catch (JMSException je) { + fail("Error setting up connection : " + je.toString()); + } + } + + public void testSendReceive() throws Exception { + sendMessage(); + + connection.start(); + consumer = consumerSession.createConsumer(queue); + consumer.setMessageListener(this); + waitForMessagesToBeDelivered(); + assertEquals("Messages received doesn't equal messages sent", messages.size(), data.length); + + } + + protected void sendMessage() throws JMSException { + messages.clear(); + try { + for (int i = 0; i < data.length; ++i) { + producer = producerSession.createProducer(queue); + objectMessage = producerSession.createObjectMessage(data[i]); + producer.send(objectMessage); + producerSession.commit(); + LOG.info("sending message :" + objectMessage); + } + } catch (Exception e) { + if (producerSession != null) { + producerSession.rollback(); + LOG.info("rollback"); + producerSession.close(); + } + + e.printStackTrace(); + } + } + + public synchronized void onMessage(Message m) { + try { + objectMessage = (ObjectMessage)m; + consumeMessage(objectMessage, messages); + + LOG.info("consumer received message :" + objectMessage); + consumerSession.commit(); + + } catch (Exception e) { + try { + consumerSession.rollback(); + LOG.info("rolled back transaction"); + } catch (JMSException e1) { + LOG.info(e1.toString()); + e1.printStackTrace(); + } + LOG.info(e.toString()); + e.printStackTrace(); + } + } + + protected void consumeMessage(Message message, List messageList) { + messageList.add(message); + if (messageList.size() >= data.length) { + synchronized (lock) { + lock.notifyAll(); + } + } + + } + + protected List createConcurrentList() { + return Collections.synchronizedList(new ArrayList()); + } + + protected void waitForMessagesToBeDelivered() { + long maxWaitTime = 5000; + long waitTime = maxWaitTime; + long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); + + synchronized (lock) { + while (messages.size() <= data.length && waitTime >= 0) { + try { + lock.wait(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + waitTime = maxWaitTime - (System.currentTimeMillis() - start); + } + } + } + + protected static void recursiveDelete(File file) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + recursiveDelete(files[i]); + } + } + file.delete(); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageTest.java new file mode 100644 index 0000000000..584af37edc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageTest.java @@ -0,0 +1,28 @@ +/** + * 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.usecases; + +/** + * + */ +public class PublishOnQueueConsumedMessageTest extends PublishOnTopicConsumedMessageTest { + + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageUsingActivemqXMLTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageUsingActivemqXMLTest.java new file mode 100644 index 0000000000..0ccbb685f7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnQueueConsumedMessageUsingActivemqXMLTest.java @@ -0,0 +1,90 @@ +/** + * 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.usecases; + +import java.io.File; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * Test Publish/Consume queue using the release activemq.xml configuration file + * + * + */ +public class PublishOnQueueConsumedMessageUsingActivemqXMLTest extends PublishOnTopicConsumedMessageTest { + protected static final String JOURNAL_ROOT = "../data/"; + private static final transient Logger LOG = LoggerFactory.getLogger(PublishOnQueueConsumedMessageUsingActivemqXMLTest.class); + BrokerService broker; + + /** + * Use the transportConnector uri configured on the activemq.xml + * + * @return ActiveMQConnectionFactory + * @throws Exception + */ + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("tcp://localhost:61616"); + } + + /** + * Sets up a test where the producer and consumer have their own connection. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + File journalFile = new File(JOURNAL_ROOT); + recursiveDelete(journalFile); + // Create broker from resource + LOG.info("Creating broker... "); + broker = createBroker("org/apache/activemq/usecases/activemq.xml"); + LOG.info("Success"); + super.setUp(); + } + + /* + * Stops the Broker + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + LOG.info("Closing Broker"); + if (broker != null) { + broker.stop(); + } + LOG.info("Broker closed..."); + } + + protected BrokerService createBroker(String resource) throws Exception { + return createBroker(new ClassPathResource(resource)); + } + + protected BrokerService createBroker(Resource resource) throws Exception { + BrokerFactoryBean factory = new BrokerFactoryBean(resource); + factory.afterPropertiesSet(); + + BrokerService broker = factory.getBroker(); + + //assertTrue("Should have a broker!", broker != null); + + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTemporaryQueueConsumedMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTemporaryQueueConsumedMessageTest.java new file mode 100644 index 0000000000..d2ee38f768 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTemporaryQueueConsumedMessageTest.java @@ -0,0 +1,31 @@ +/** + * 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.usecases; + +import javax.jms.DeliveryMode; + +/** + * + */ +public class PublishOnTemporaryQueueConsumedMessageTest extends PublishOnTopicConsumedMessageTest { + + protected void setUp() throws Exception { + topic = false; + deliveryMode = DeliveryMode.NON_PERSISTENT; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTopicConsumedMessageTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTopicConsumedMessageTest.java new file mode 100644 index 0000000000..f28a48033a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTopicConsumedMessageTest.java @@ -0,0 +1,67 @@ +/** + * 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.usecases; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; + +import org.apache.activemq.test.JmsTopicSendReceiveWithTwoConnectionsTest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class PublishOnTopicConsumedMessageTest extends JmsTopicSendReceiveWithTwoConnectionsTest { + + private static final Logger LOG = LoggerFactory.getLogger(PublishOnTopicConsumedMessageTest.class); + + private MessageProducer replyProducer; + + public synchronized void onMessage(Message message) { + + // lets resend the message somewhere else + try { + Message msgCopy = (Message)((org.apache.activemq.command.Message)message).copy(); + replyProducer.send(msgCopy); + + // log.info("Sending reply: " + message); + super.onMessage(message); + } catch (JMSException e) { + LOG.info("Failed to send message: " + e); + e.printStackTrace(); + } + } + + protected void setUp() throws Exception { + super.setUp(); + + Destination replyDestination = null; + + if (topic) { + replyDestination = receiveSession.createTopic("REPLY." + getSubject()); + } else { + replyDestination = receiveSession.createQueue("REPLY." + getSubject()); + } + + replyProducer = receiveSession.createProducer(replyDestination); + LOG.info("Created replyProducer: " + replyProducer); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTopicConsumerMessageUsingActivemqXMLTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTopicConsumerMessageUsingActivemqXMLTest.java new file mode 100644 index 0000000000..d904d12e10 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/PublishOnTopicConsumerMessageUsingActivemqXMLTest.java @@ -0,0 +1,91 @@ +/** + * 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.usecases; + +import java.io.File; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * Test Publish/Consume topic using the release activemq.xml configuration file + * + * + */ +public class PublishOnTopicConsumerMessageUsingActivemqXMLTest extends PublishOnTopicConsumedMessageTest { + protected static final String JOURNAL_ROOT = "../data/"; + private static final transient Logger LOG = LoggerFactory.getLogger(PublishOnTopicConsumerMessageUsingActivemqXMLTest.class); + + BrokerService broker; + + /** + * Use the transportConnector uri configured on the activemq.xml + * + * @return ActiveMQConnectionFactory + * @throws Exception + */ + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("tcp://localhost:61616"); + } + + /** + * Sets up a test where the producer and consumer have their own connection. + * + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + File journalFile = new File(JOURNAL_ROOT); + recursiveDelete(journalFile); + // Create broker from resource + LOG.info("Creating broker... "); + broker = createBroker("org/apache/activemq/usecases/activemq.xml"); + LOG.info("Success"); + super.setUp(); + } + + /* + * Stops the Broker + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + LOG.info("Closing Broker"); + if (broker != null) { + broker.stop(); + } + LOG.info("Broker closed..."); + } + + protected BrokerService createBroker(String resource) throws Exception { + return createBroker(new ClassPathResource(resource)); + } + + protected BrokerService createBroker(Resource resource) throws Exception { + BrokerFactoryBean factory = new BrokerFactoryBean(resource); + factory.afterPropertiesSet(); + + BrokerService broker = factory.getBroker(); + + //assertTrue("Should have a broker!", broker != null); + + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingLevelDBTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingLevelDBTest.java new file mode 100644 index 0000000000..55a9bfd8fb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingLevelDBTest.java @@ -0,0 +1,36 @@ +/** + * 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.usecases; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; + +import java.io.File; +import java.io.IOException; + +public class QueueBrowsingLevelDBTest extends QueueBrowsingTest { + + @Override + public BrokerService createBroker() throws IOException { + BrokerService broker = super.createBroker(); + LevelDBStore store = new LevelDBStore(); + store.setDirectory(new File("target/test-data/leveldb")); + broker.setPersistenceAdapter(store); + return broker; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingLimitTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingLimitTest.java new file mode 100644 index 0000000000..15df78cf53 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingLimitTest.java @@ -0,0 +1,113 @@ +/** + * 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.usecases; + +import java.io.IOException; +import java.net.URI; +import java.util.Enumeration; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import static org.junit.Assert.assertEquals; + +public class QueueBrowsingLimitTest { + + private static final Logger LOG = LoggerFactory.getLogger(QueueBrowsingLimitTest.class); + + private BrokerService broker; + private URI connectUri; + private ActiveMQConnectionFactory factory; + private final int browserLimit = 300; + + + @Before + public void startBroker() throws Exception { + broker = createBroker(); + TransportConnector connector = broker.addConnector("tcp://0.0.0.0:0"); + broker.deleteAllMessages(); + broker.start(); + broker.waitUntilStarted(); + + PolicyEntry policy = new PolicyEntry(); + policy.setMaxBrowsePageSize(browserLimit); + broker.setDestinationPolicy(new PolicyMap()); + broker.getDestinationPolicy().setDefaultEntry(policy); + + connectUri = connector.getConnectUri(); + factory = new ActiveMQConnectionFactory(connectUri); + + } + + public BrokerService createBroker() throws IOException { + return new BrokerService(); + } + + @After + public void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testBrowsingLimited() throws Exception { + + int messageToSend = 470; + + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + + String data = ""; + for( int i=0; i < 1024*2; i++ ) { + data += "x"; + } + + for( int i=0; i < messageToSend; i++ ) { + producer.send(session.createTextMessage(data)); + } + + QueueBrowser browser = session.createBrowser(queue); + Enumeration enumeration = browser.getEnumeration(); + int received = 0; + while (enumeration.hasMoreElements()) { + Message m = (Message) enumeration.nextElement(); + received++; + LOG.info("Browsed message " + received + ": " + m.getJMSMessageID()); + } + + browser.close(); + + assertEquals(browserLimit, received); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingTest.java new file mode 100644 index 0000000000..29b6e7297c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueBrowsingTest.java @@ -0,0 +1,216 @@ +/** + * 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.usecases; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +import java.io.IOException; +import java.net.URI; +import java.util.Enumeration; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.QueueBrowser; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QueueBrowsingTest { + + private static final Logger LOG = LoggerFactory.getLogger(QueueBrowsingTest.class); + + private BrokerService broker; + private URI connectUri; + private ActiveMQConnectionFactory factory; + private final int maxPageSize = 100; + + @Before + public void startBroker() throws Exception { + broker = createBroker(); + TransportConnector connector = broker.addConnector("tcp://0.0.0.0:0"); + broker.deleteAllMessages(); + broker.start(); + broker.waitUntilStarted(); + + PolicyEntry policy = new PolicyEntry(); + policy.setMaxPageSize(maxPageSize); + broker.setDestinationPolicy(new PolicyMap()); + broker.getDestinationPolicy().setDefaultEntry(policy); + + connectUri = connector.getConnectUri(); + factory = new ActiveMQConnectionFactory(connectUri); + } + + public BrokerService createBroker() throws IOException { + return new BrokerService(); + } + + @After + public void stopBroker() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + @Test + public void testBrowsing() throws JMSException { + + int messageToSend = 370; + + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + + String data = ""; + for( int i=0; i < 1024*2; i++ ) { + data += "x"; + } + + for( int i=0; i < messageToSend; i++ ) { + producer.send(session.createTextMessage(data)); + } + + QueueBrowser browser = session.createBrowser(queue); + Enumeration enumeration = browser.getEnumeration(); + int received = 0; + while (enumeration.hasMoreElements()) { + Message m = (Message) enumeration.nextElement(); + received++; + LOG.info("Browsed message " + received + ": " + m.getJMSMessageID()); + } + + browser.close(); + + assertEquals(messageToSend, received); + } + + @Test + public void testBrowseConcurrent() throws Exception { + final int messageToSend = 370; + + final ActiveMQQueue queue = new ActiveMQQueue("TEST"); + Connection connection = factory.createConnection(); + connection.start(); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = session.createProducer(queue); + + String data = ""; + for( int i=0; i < 1024*2; i++ ) { + data += "x"; + } + + for( int i=0; i < messageToSend; i++ ) { + producer.send(session.createTextMessage(data)); + } + + Thread browserThread = new Thread() { + @Override + public void run() { + try { + QueueBrowser browser = session.createBrowser(queue); + Enumeration enumeration = browser.getEnumeration(); + int received = 0; + while (enumeration.hasMoreElements()) { + Message m = (Message) enumeration.nextElement(); + received++; + LOG.info("Browsed message " + received + ": " + m.getJMSMessageID()); + } + assertEquals("Browsed all messages", messageToSend, received); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + browserThread.start(); + + Thread consumerThread = new Thread() { + @Override + public void run() { + try { + MessageConsumer consumer = session.createConsumer(queue); + int received = 0; + while (true) { + Message m = consumer.receive(1000); + if (m == null) + break; + received++; + } + assertEquals("Consumed all messages", messageToSend, received); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + consumerThread.start(); + + browserThread.join(); + consumerThread.join(); + } + + @Test + public void testMemoryLimit() throws Exception { + broker.getSystemUsage().getMemoryUsage().setLimit(16 * 1024); + + int messageToSend = 370; + + ActiveMQQueue queue = new ActiveMQQueue("TEST"); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(queue); + + String data = ""; + for( int i=0; i < 1024*2; i++ ) { + data += "x"; + } + + for( int i=0; i < messageToSend; i++ ) { + producer.send(session.createTextMessage(data)); + } + + QueueBrowser browser = session.createBrowser(queue); + Enumeration enumeration = browser.getEnumeration(); + int received = 0; + while (enumeration.hasMoreElements()) { + Message m = (Message) enumeration.nextElement(); + received++; + LOG.info("Browsed message " + received + ": " + m.getJMSMessageID()); + } + + browser.close(); + assertTrue("got at least maxPageSize", received >= maxPageSize); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueConsumerCloseAndReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueConsumerCloseAndReconnectTest.java new file mode 100644 index 0000000000..73fa27ae52 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueConsumerCloseAndReconnectTest.java @@ -0,0 +1,26 @@ +/** + * 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.usecases; + +/** + * + */ +public class QueueConsumerCloseAndReconnectTest extends DurableConsumerCloseAndReconnectTest { + protected boolean isTopic() { + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueDuplicatesTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueDuplicatesTest.java new file mode 100644 index 0000000000..1084ce9457 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueDuplicatesTest.java @@ -0,0 +1,158 @@ +/** + * 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.usecases; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QueueDuplicatesTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(QueueDuplicatesTest.class); + + private static DateFormat formatter = new SimpleDateFormat("HH:mm:ss SSS"); + private String brokerUrl; + private String subject; + private Connection brokerConnection; + + public QueueDuplicatesTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + String peerUrl = "peer://localhost:6099"; + + subject = this.getClass().getName(); + + ActiveMQConnectionFactory fac = createFactory(peerUrl); + brokerConnection = fac.createConnection(); + brokerConnection.start(); + } + + protected void tearDown() throws Exception { + if (brokerConnection != null) { + brokerConnection.close(); + } + } + + public void testDuplicates() { + try { + // Get Session + Session session = createSession(brokerConnection); + // create consumer + Destination dest = session.createQueue(subject); + MessageConsumer consumer = session.createConsumer(dest); + // subscribe to queue + consumer.setMessageListener(new SimpleConsumer()); + // create producer + Thread sendingThread = new SendingThread(brokerUrl, subject); + // start producer + sendingThread.start(); + // wait about 5 seconds + Thread.sleep(5000); + // unsubscribe consumer + consumer.close(); + // wait another 5 seconds + Thread.sleep(5000); + // create new consumer + consumer = session.createConsumer(dest); + // subscribe to queue + consumer.setMessageListener(new SimpleConsumer()); + // sleep a little while longer + Thread.sleep(15000); + session.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + Session createSession(Connection peerConnection) throws JMSException { + // Connect using peer to peer connection + Session session = peerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + return session; + } + + private ActiveMQConnectionFactory createFactory(String brokerUrl) { + ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); + cf.setBrokerURL(brokerUrl); + + return cf; + } + + private class SendingThread extends Thread { + private String subject; + + SendingThread(String brokerUrl, String subject) { + this.subject = subject; + setDaemon(false); + } + + public void run() { + try { + Session session = createSession(brokerConnection); + Destination dest = session.createQueue(subject); + MessageProducer producer = session.createProducer(dest); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + for (int i = 0; i < 20; i++) { + String txt = "Text Message: " + i; + TextMessage msg = session.createTextMessage(txt); + producer.send(msg); + LOG.info(formatter.format(new Date()) + " Sent ==> " + msg + " to " + subject); + Thread.sleep(1000); + } + session.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private static class SimpleConsumer implements MessageListener { + private Map msgs = new HashMap(); + + public void onMessage(Message message) { + LOG.info(formatter.format(new Date()) + " SimpleConsumer Message Received: " + message); + try { + String id = message.getJMSMessageID(); + assertNull("Message is duplicate: " + id, msgs.get(id)); + msgs.put(id, message); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueMemoryFullMultiBrokersTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueMemoryFullMultiBrokersTest.java new file mode 100644 index 0000000000..42776a48f1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueMemoryFullMultiBrokersTest.java @@ -0,0 +1,100 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Destination; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.usage.SystemUsage; + +public class QueueMemoryFullMultiBrokersTest extends JmsMultipleBrokersTestSupport { + public static final int BROKER_COUNT = 2; + public static final int MESSAGE_COUNT = 2000; + + public void testQueueNetworkWithConsumerFull() throws Exception { + + bridgeAllBrokers(); + startAllBrokers(); + + Destination dest = createDestination("TEST.FOO", false); + + sendMessages("Broker1", dest, 50); + + CountDownLatch latch = new CountDownLatch(MESSAGE_COUNT); + createConsumer("Broker2", dest, latch); + assertConsumersConnect("Broker1", dest, 1, 30000); + sendMessages("Broker1", dest, MESSAGE_COUNT - 50); + + // Wait for messages to be delivered + assertTrue("Missing " + latch.getCount() + " messages", latch.await(45, TimeUnit.SECONDS)); + + // verify stats, all messages acked + BrokerService broker1 = brokers.get("Broker1").broker; + RegionBroker regionBroker = (RegionBroker) broker1.getRegionBroker(); + // give the acks a chance to flow + Thread.sleep(2000); + Queue internalQueue = (Queue) regionBroker.getDestinations(ActiveMQDestination.transform(dest)).iterator().next(); + + assertTrue("All messages are consumed and acked from source:" + internalQueue, internalQueue.getMessages().isEmpty()); + assertEquals("messages source:" + internalQueue, 0, internalQueue.getDestinationStatistics().getMessages().getCount()); + assertEquals("inflight source:" + internalQueue, 0, internalQueue.getDestinationStatistics().getInflight().getCount()); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + messageSize = 1024; + + // Setup n brokers + for (int i = 1; i <= BROKER_COUNT; i++) { + createBroker(new URI("broker:()/Broker" + i + "?persistent=false&useJmx=false")); + } + BrokerService broker2 = brokers.get("Broker2").broker; + applyMemoryLimitPolicy(broker2); + } + + private void applyMemoryLimitPolicy(BrokerService broker) { + final SystemUsage memoryManager = new SystemUsage(); + memoryManager.getMemoryUsage().setLimit(1024 * 50); // 50 MB + broker.setSystemUsage(memoryManager); + + final List policyEntries = new ArrayList(); + final PolicyEntry entry = new PolicyEntry(); + entry.setQueue(">"); + entry.setMemoryLimit(1024 * 4); // Set to 2 kb + entry.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy()); + policyEntries.add(entry); + + final PolicyMap policyMap = new PolicyMap(); + policyMap.setPolicyEntries(policyEntries); + broker.setDestinationPolicy(policyMap); + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueRedeliverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueRedeliverTest.java new file mode 100644 index 0000000000..b9f821a98f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueRedeliverTest.java @@ -0,0 +1,29 @@ +/** + * 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.usecases; + +/** + * + */ +public class QueueRedeliverTest extends TopicRedeliverTest { + + protected void setUp() throws Exception { + super.setUp(); + topic = false; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueRepeaterTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueRepeaterTest.java new file mode 100644 index 0000000000..dcd32fcba6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/QueueRepeaterTest.java @@ -0,0 +1,119 @@ +/** + * 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.usecases; + +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author pragmasoft + * + */ +public final class QueueRepeaterTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(QueueRepeaterTest.class); + + private volatile String receivedText; + + private Session producerSession; + private Session consumerSession; + private Destination queue; + + private MessageProducer producer; + private MessageConsumer consumer; + private Connection connection; + private CountDownLatch latch = new CountDownLatch(1); + + public void testTransaction() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = factory.createConnection(); + queue = new ActiveMQQueue(getClass().getName() + "." + getName()); + + producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerSession = connection.createSession(true, 0); + + producer = producerSession.createProducer(queue); + + consumer = consumerSession.createConsumer(queue); + consumer.setMessageListener(new MessageListener() { + + public void onMessage(Message m) { + try { + TextMessage tm = (TextMessage)m; + receivedText = tm.getText(); + latch.countDown(); + + LOG.info("consumer received message :" + receivedText); + consumerSession.commit(); + LOG.info("committed transaction"); + } catch (JMSException e) { + try { + consumerSession.rollback(); + LOG.info("rolled back transaction"); + } catch (JMSException e1) { + LOG.info(e1.toString()); + e1.printStackTrace(); + } + LOG.info(e.toString()); + e.printStackTrace(); + } + } + }); + + connection.start(); + + TextMessage tm = null; + try { + tm = producerSession.createTextMessage(); + tm.setText("Hello, " + new Date()); + producer.send(tm); + LOG.info("producer sent message :" + tm.getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + + LOG.info("Waiting for latch"); + latch.await(2,TimeUnit.SECONDS); + assertNotNull(receivedText); + LOG.info("test completed, destination=" + receivedText); + } + + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ReliableReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ReliableReconnectTest.java new file mode 100644 index 0000000000..05fd5f847a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ReliableReconnectTest.java @@ -0,0 +1,179 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.util.IdGenerator; + +public class ReliableReconnectTest extends org.apache.activemq.TestSupport { + + protected static final int MESSAGE_COUNT = 100; + protected static final String DEFAULT_BROKER_URL = ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL; + private static final int RECEIVE_TIMEOUT = 10000; + + protected int deliveryMode = DeliveryMode.PERSISTENT; + protected String consumerClientId; + protected Destination destination; + protected AtomicBoolean closeBroker = new AtomicBoolean(false); + protected AtomicInteger messagesReceived = new AtomicInteger(0); + protected BrokerService broker; + protected int firstBatch = MESSAGE_COUNT / 10; + private IdGenerator idGen = new IdGenerator(); + + public ReliableReconnectTest() { + } + + protected void setUp() throws Exception { + this.setAutoFail(true); + consumerClientId = idGen.generateId(); + super.setUp(); + topic = true; + destination = createDestination(getClass().getName()); + } + + protected void tearDown() throws Exception { + if (broker!=null) { + broker.stop(); + } + } + + public ActiveMQConnectionFactory getConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory(); + } + + protected void startBroker(boolean deleteOnStart) throws JMSException { + try { + broker = BrokerFactory.createBroker(new URI("broker://()/localhost")); + broker.setUseShutdownHook(false); + broker.setDeleteAllMessagesOnStartup(deleteOnStart); + + broker.setUseJmx(false); + broker.addConnector(DEFAULT_BROKER_URL); + broker.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + protected Connection createConsumerConnection() throws Exception { + Connection consumerConnection = getConnectionFactory().createConnection(); + consumerConnection.setClientID(consumerClientId); + consumerConnection.start(); + return consumerConnection; + } + + protected MessageConsumer createConsumer(Connection con) throws Exception { + Session s = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + return s.createDurableSubscriber((Topic)destination, "TestFred"); + } + + protected void spawnConsumer() { + Thread thread = new Thread(new Runnable() { + public void run() { + try { + Connection consumerConnection = createConsumerConnection(); + MessageConsumer consumer = createConsumer(consumerConnection); + // consume some messages + + for (int i = 0; i < firstBatch; i++) { + Message msg = consumer.receive(RECEIVE_TIMEOUT); + if (msg != null) { + // log.info("GOT: " + msg); + messagesReceived.incrementAndGet(); + } + } + synchronized (closeBroker) { + closeBroker.set(true); + closeBroker.notify(); + } + Thread.sleep(2000); + for (int i = firstBatch; i < MESSAGE_COUNT; i++) { + Message msg = consumer.receive(RECEIVE_TIMEOUT); + // log.info("GOT: " + msg); + if (msg != null) { + messagesReceived.incrementAndGet(); + } + } + consumerConnection.close(); + synchronized (messagesReceived) { + messagesReceived.notify(); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); + thread.start(); + } + + public void testReconnect() throws Exception { + startBroker(true); + // register an interest as a durable subscriber + Connection consumerConnection = createConsumerConnection(); + createConsumer(consumerConnection); + consumerConnection.close(); + // send some messages ... + Connection connection = createConnection(); + connection.setClientID(idGen.generateId()); + connection.start(); + Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(destination); + TextMessage msg = producerSession.createTextMessage(); + for (int i = 0; i < MESSAGE_COUNT; i++) { + msg.setText("msg: " + i); + producer.send(msg); + } + connection.close(); + spawnConsumer(); + synchronized (closeBroker) { + if (!closeBroker.get()) { + closeBroker.wait(); + } + } + // System.err.println("Stopping broker"); + broker.stop(); + startBroker(false); + // System.err.println("Started Broker again"); + synchronized (messagesReceived) { + if (messagesReceived.get() < MESSAGE_COUNT) { + messagesReceived.wait(60000); + } + } + // assertTrue(messagesReceived.get() == MESSAGE_COUNT); + int count = messagesReceived.get(); + assertTrue("Not enough messages received: " + count, count > firstBatch); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyNoAdvisoryNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyNoAdvisoryNetworkTest.java new file mode 100644 index 0000000000..9670d4080f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyNoAdvisoryNetworkTest.java @@ -0,0 +1,281 @@ +/** + * 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.usecases; + + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.util.Map; +import java.util.Vector; + +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTempQueue; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; +import org.apache.activemq.xbean.XBeanBrokerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RequestReplyNoAdvisoryNetworkTest extends JmsMultipleBrokersTestSupport { + private static final transient Logger LOG = LoggerFactory.getLogger(RequestReplyNoAdvisoryNetworkTest.class); + + Vector brokers = new Vector(); + BrokerService a, b; + ActiveMQQueue sendQ = new ActiveMQQueue("sendQ"); + static final String connectionIdMarker = "ID:marker."; + ActiveMQTempQueue replyQWildcard = new ActiveMQTempQueue(connectionIdMarker + ">"); + private final long receiveTimeout = 30000; + + public void testNonAdvisoryNetworkRequestReplyXmlConfig() throws Exception { + final String xmlConfigString = new String( + "" + + " " + + " " + + " " + + " " + + " "+ + " "+ + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""); + final String localProtocolScheme = "inline"; + URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() { + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + if (localProtocolScheme.equalsIgnoreCase(protocol)) { + return new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL u) throws IOException { + return new URLConnection(u) { + @Override + public void connect() throws IOException { + } + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(xmlConfigString.replace("%HOST%", url.getFile()).getBytes("UTF-8")); + } + }; + } + }; + } + return null; + } + }); + a = new XBeanBrokerFactory().createBroker(new URI("xbean:" + localProtocolScheme + ":A")); + b = new XBeanBrokerFactory().createBroker(new URI("xbean:" + localProtocolScheme + ":B")); + brokers.add(a); + brokers.add(b); + + doTestNonAdvisoryNetworkRequestReply(); + } + + public void testNonAdvisoryNetworkRequestReply() throws Exception { + createBridgeAndStartBrokers(); + doTestNonAdvisoryNetworkRequestReply(); + } + + public void testNonAdvisoryNetworkRequestReplyWithPIM() throws Exception { + a = configureBroker("A"); + b = configureBroker("B"); + BrokerService hub = configureBroker("M"); + hub.setAllowTempAutoCreationOnSend(true); + configureForPiggyInTheMiddle(bridge(a, hub)); + configureForPiggyInTheMiddle(bridge(b, hub)); + + startBrokers(); + + waitForBridgeFormation(hub, 2, 0); + doTestNonAdvisoryNetworkRequestReply(); + } + + private void configureForPiggyInTheMiddle(NetworkConnector bridge) { + bridge.setDuplex(true); + bridge.setNetworkTTL(2); + } + + public void doTestNonAdvisoryNetworkRequestReply() throws Exception { + + waitForBridgeFormation(a, 1, 0); + waitForBridgeFormation(b, 1, 0); + + ActiveMQConnectionFactory sendFactory = createConnectionFactory(a); + ActiveMQConnection sendConnection = createConnection(sendFactory); + + ActiveMQSession sendSession = (ActiveMQSession)sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = sendSession.createProducer(sendQ); + ActiveMQTempQueue realReplyQ = (ActiveMQTempQueue) sendSession.createTemporaryQueue(); + TextMessage message = sendSession.createTextMessage("1"); + message.setJMSReplyTo(realReplyQ); + producer.send(message); + LOG.info("request sent"); + + // responder + ActiveMQConnectionFactory consumerFactory = createConnectionFactory(b); + ActiveMQConnection consumerConnection = createConnection(consumerFactory); + + ActiveMQSession consumerSession = (ActiveMQSession)consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(sendQ); + TextMessage received = (TextMessage) consumer.receive(receiveTimeout); + assertNotNull("got request from sender ok", received); + + LOG.info("got request, sending reply"); + + MessageProducer consumerProducer = consumerSession.createProducer(received.getJMSReplyTo()); + consumerProducer.send(consumerSession.createTextMessage("got " + received.getText())); + // temp dest on reply broker tied to this connection, setOptimizedDispatch=true ensures + // message gets delivered before destination is removed + consumerConnection.close(); + + // reply consumer + MessageConsumer replyConsumer = sendSession.createConsumer(realReplyQ); + TextMessage reply = (TextMessage) replyConsumer.receive(receiveTimeout); + assertNotNull("expected reply message", reply); + assertEquals("text is as expected", "got 1", reply.getText()); + sendConnection.close(); + + LOG.info("checking for dangling temp destinations"); + // ensure all temp dests get cleaned up on all brokers + for (BrokerService brokerService : brokers) { + final RegionBroker regionBroker = (RegionBroker) brokerService.getRegionBroker(); + assertTrue("all temps are gone on " + regionBroker.getBrokerName(), Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + Map tempTopics = regionBroker.getTempTopicRegion().getDestinationMap(); + LOG.info("temp topics on " + regionBroker.getBrokerName() + ", " + tempTopics); + Map tempQ = regionBroker.getTempQueueRegion().getDestinationMap(); + LOG.info("temp queues on " + regionBroker.getBrokerName() + ", " + tempQ); + return tempQ.isEmpty() && tempTopics.isEmpty(); + } + })); + } + } + + private ActiveMQConnection createConnection(ActiveMQConnectionFactory factory) throws Exception { + ActiveMQConnection c =(ActiveMQConnection) factory.createConnection(); + c.start(); + return c; + } + + private ActiveMQConnectionFactory createConnectionFactory(BrokerService brokerService) throws Exception { + String target = brokerService.getTransportConnectors().get(0).getPublishableConnectString(); + ActiveMQConnectionFactory factory = + new ActiveMQConnectionFactory(target); + factory.setWatchTopicAdvisories(false); + factory.setConnectionIDPrefix(connectionIdMarker + brokerService.getBrokerName()); + return factory; + } + + public void createBridgeAndStartBrokers() throws Exception { + a = configureBroker("A"); + b = configureBroker("B"); + bridge(a, b); + bridge(b, a); + startBrokers(); + } + + private void startBrokers() throws Exception { + for (BrokerService broker: brokers) { + broker.start(); + } + } + + @Override + public void tearDown() throws Exception { + for (BrokerService broker: brokers) { + broker.stop(); + } + brokers.clear(); + } + + + private NetworkConnector bridge(BrokerService from, BrokerService to) throws Exception { + TransportConnector toConnector = to.getTransportConnectors().get(0); + NetworkConnector bridge = + from.addNetworkConnector("static://" + toConnector.getPublishableConnectString()); + bridge.addStaticallyIncludedDestination(sendQ); + bridge.addStaticallyIncludedDestination(replyQWildcard); + return bridge; + } + + private BrokerService configureBroker(String brokerName) throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName(brokerName); + broker.setAdvisorySupport(false); + broker.setPersistent(false); + broker.setUseJmx(false); + broker.setSchedulePeriodForDestinationPurge(1000); + broker.setAllowTempAutoCreationOnSend(true); + + PolicyMap map = new PolicyMap(); + PolicyEntry tempReplyQPolicy = new PolicyEntry(); + tempReplyQPolicy.setOptimizedDispatch(true); + tempReplyQPolicy.setGcInactiveDestinations(true); + tempReplyQPolicy.setGcWithNetworkConsumers(true); + tempReplyQPolicy.setInactiveTimoutBeforeGC(1000); + map.put(replyQWildcard, tempReplyQPolicy); + broker.setDestinationPolicy(map); + + broker.addConnector("tcp://localhost:0"); + brokers.add(broker); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyTempDestRemovalAdvisoryRaceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyTempDestRemovalAdvisoryRaceTest.java new file mode 100644 index 0000000000..4822e0250f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyTempDestRemovalAdvisoryRaceTest.java @@ -0,0 +1,486 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Random; +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.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.region.policy.DeadLetterStrategy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.broker.region.policy.PriorityDispatchPolicy; +import org.apache.activemq.broker.region.policy.SharedDeadLetterStrategy; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTempTopic; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.apache.activemq.network.DemandForwardingBridgeSupport; +import org.apache.activemq.network.NetworkBridge; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.DefaultTestAppender; +import org.apache.log4j.Appender; +import org.apache.log4j.Level; +import org.apache.log4j.spi.LoggingEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Christian Posta + */ +public class RequestReplyTempDestRemovalAdvisoryRaceTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(RequestReplyTempDestRemovalAdvisoryRaceTest.class); + + private static final String BROKER_A = "BrokerA"; + private static final String BROKER_B = "BrokerB"; + private static final String BROKER_C = "BrokerC"; + + private static final int NUM_RESPONDENTS = 1; + private static final int NUM_SENDS = 1; + private static final int RANDOM_SLEEP_FOR_RESPONDENT_MS = 0; + private static final int RANDOM_SLEEP_FOR_SENDER_MS = 1; + private static final String QUEUE_NAME = "foo.queue"; + private static String[] TEST_ITERATIONS = new String[]{QUEUE_NAME+"0", QUEUE_NAME+"1", QUEUE_NAME+"2", QUEUE_NAME+"3"}; + + final AtomicLong messageCount = new AtomicLong(0); + final AtomicLong respondentSendError = new AtomicLong(0); + final AtomicLong responseReceived = new AtomicLong(0); + final AtomicLong sendsWithNoConsumers = new AtomicLong(0); + final AtomicLong forwardFailures = new AtomicLong(0); + + + protected final AtomicBoolean shutdown = new AtomicBoolean(false); + HashSet networkConnectors = new HashSet(); + HashSet advisoryConsumerConnections = new HashSet(); + Appender slowDownAppender; + + CountDownLatch consumerDemandExists; + + protected boolean useDuplex = false; + + public static Test suite() { + return suite(RequestReplyTempDestRemovalAdvisoryRaceTest.class); + } + + /** + * Notes: to reliably reproduce use debugger... set a "thread" breakpoint at line 679 in DemandForwardingBridgeSupport, + * and only break on the "2nd" pass (broker C's bridge). Allow debugging to continue shortly after hitting + * the breakpoint, for this test we use a logging appender to implement the pause, + * it fails most of the time, hence the combos + */ + public void initCombos() { + addCombinationValues("QUEUE_NAME", TEST_ITERATIONS); + } + + public void testTempDestRaceDuplex() throws Exception { + // duplex + useDuplex = true; + bridgeBrokers(BROKER_A, BROKER_B, false, 3); + bridgeBrokers(BROKER_B, BROKER_C, false, 3); + + startAllBrokers(); + + waitForBridgeFormation(1); + + HashSet bridgesStart = new HashSet(); + for (NetworkConnector networkConnector : networkConnectors) { + bridgesStart.addAll(networkConnector.activeBridges()); + } + LOG.info("Bridges start:" + bridgesStart); + + slowDownAdvisoryDispatch(); + noConsumerAdvisory(); + forwardFailureAdvisory(); + + // set up respondents + ExecutorService respondentThreadPool = Executors.newFixedThreadPool(50); + BrokerItem brokerA = brokers.get(BROKER_A); + ActiveMQConnectionFactory brokerAFactory = new ActiveMQConnectionFactory(brokerA.broker.getTransportConnectorByScheme("tcp").getName() + + "?jms.watchTopicAdvisories=false"); + brokerAFactory.setAlwaysSyncSend(true); + for (int i = 0; i < NUM_RESPONDENTS; i++) { + respondentThreadPool.execute(new EchoRespondent(brokerAFactory)); + } + + // fire off sends + ExecutorService senderThreadPool = Executors.newCachedThreadPool(); + BrokerItem brokerC = brokers.get(BROKER_C); + ActiveMQConnectionFactory brokerCFactory = new ActiveMQConnectionFactory(brokerC.broker.getTransportConnectorByScheme("tcp").getName() + + "?jms.watchTopicAdvisories=false"); + for (int i = 0; i < NUM_SENDS; i++) { + senderThreadPool.execute(new MessageSender(brokerCFactory)); + } + + senderThreadPool.shutdown(); + senderThreadPool.awaitTermination(30, TimeUnit.SECONDS); + TimeUnit.SECONDS.sleep(15); + LOG.info("shutting down"); + shutdown.compareAndSet(false, true); + + HashSet bridgesEnd = new HashSet(); + for (NetworkConnector networkConnector : networkConnectors) { + bridgesEnd.addAll(networkConnector.activeBridges()); + } + LOG.info("Bridges end:" + bridgesEnd); + + assertEquals("no new bridges created", bridgesStart, bridgesEnd); + + // validate success or error of dlq + LOG.info("received: " + responseReceived.get() + ", respondent error: " + respondentSendError.get() + + ", noConsumerCount: " + sendsWithNoConsumers.get() + + ", forwardFailures: " + forwardFailures.get()); + assertEquals("success or error", NUM_SENDS, respondentSendError.get() + forwardFailures.get() + + responseReceived.get() + sendsWithNoConsumers.get()); + + } + + private void forwardFailureAdvisory() throws JMSException { + for (BrokerItem item : brokers.values()) { + ActiveMQConnectionFactory brokerAFactory = new ActiveMQConnectionFactory(item.broker.getTransportConnectorByScheme("tcp").getName() + + "?jms.watchTopicAdvisories=false"); + Connection connection = brokerAFactory.createConnection(); + connection.start(); + connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer( + AdvisorySupport.getNetworkBridgeForwardFailureAdvisoryTopic()).setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + forwardFailures.incrementAndGet(); + } + }); + } + } + + private void noConsumerAdvisory() throws JMSException { + for (BrokerItem item : brokers.values()) { + ActiveMQConnectionFactory brokerAFactory = new ActiveMQConnectionFactory(item.broker.getTransportConnectorByScheme("tcp").getName() + + "?jms.watchTopicAdvisories=false"); + Connection connection = brokerAFactory.createConnection(); + connection.start(); + connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer( + AdvisorySupport.getNoTopicConsumersAdvisoryTopic(new ActiveMQTempTopic(">"))).setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + sendsWithNoConsumers.incrementAndGet(); + } + }); + } + } + + + public void testTempDestRace() throws Exception { + // non duplex + bridgeBrokers(BROKER_A, BROKER_B, false, 3); + bridgeBrokers(BROKER_B, BROKER_A, false, 3); + bridgeBrokers(BROKER_B, BROKER_C, false, 3); + bridgeBrokers(BROKER_C, BROKER_B, false, 3); + + startAllBrokers(); + + waitForBridgeFormation(1); + + HashSet bridgesStart = new HashSet(); + for (NetworkConnector networkConnector : networkConnectors) { + bridgesStart.addAll(networkConnector.activeBridges()); + } + + slowDownAdvisoryDispatch(); + noConsumerAdvisory(); + forwardFailureAdvisory(); + + + // set up respondents + ExecutorService respondentThreadPool = Executors.newFixedThreadPool(50); + BrokerItem brokerA = brokers.get(BROKER_A); + ActiveMQConnectionFactory brokerAFactory = new ActiveMQConnectionFactory(brokerA.broker.getTransportConnectorByScheme("tcp").getName() + + "?jms.watchTopicAdvisories=false"); + brokerAFactory.setAlwaysSyncSend(true); + for (int i = 0; i < NUM_RESPONDENTS; i++) { + respondentThreadPool.execute(new EchoRespondent(brokerAFactory)); + } + + // fire off sends + ExecutorService senderThreadPool = Executors.newCachedThreadPool(); + BrokerItem brokerC = brokers.get(BROKER_C); + ActiveMQConnectionFactory brokerCFactory = new ActiveMQConnectionFactory(brokerC.broker.getTransportConnectorByScheme("tcp").getName() + + "?jms.watchTopicAdvisories=false"); + for (int i = 0; i < NUM_SENDS; i++) { + senderThreadPool.execute(new MessageSender(brokerCFactory)); + } + + senderThreadPool.shutdown(); + senderThreadPool.awaitTermination(30, TimeUnit.SECONDS); + TimeUnit.SECONDS.sleep(10); + LOG.info("shutting down"); + shutdown.compareAndSet(false, true); + + HashSet bridgesEnd = new HashSet(); + for (NetworkConnector networkConnector : networkConnectors) { + bridgesEnd.addAll(networkConnector.activeBridges()); + } + assertEquals("no new bridges created", bridgesStart, bridgesEnd); + + // validate success or error or dlq + LOG.info("received: " + responseReceived.get() + ", respondent error: " + respondentSendError.get() + + ", noConsumerCount: " + sendsWithNoConsumers.get() + + ", forwardFailures: " + forwardFailures.get()); + assertEquals("success or error", NUM_SENDS, respondentSendError.get() + forwardFailures.get() + + responseReceived.get() + sendsWithNoConsumers.get()); + + } + + private void slowDownAdvisoryDispatch() throws Exception { + + org.apache.log4j.Logger.getLogger(DemandForwardingBridgeSupport.class).setLevel(Level.DEBUG); + + // instrument a logger to block the processing of a remove sub advisory + // simulate a slow thread + slowDownAppender = new DefaultTestAppender() { + @Override + public void doAppend(LoggingEvent loggingEvent) { + if (Level.DEBUG.equals(loggingEvent.getLevel())) { + String message = loggingEvent.getMessage().toString(); + if (message.startsWith("BrokerB") && message.contains("remove local subscription")) { + // sleep for a bit + try { + consumerDemandExists.countDown(); + System.err.println("Sleeping on receipt of remove info debug message: " + message); + TimeUnit.SECONDS.sleep(2); + } catch (Exception ignored) { + } + } + + } + } + }; + + org.apache.log4j.Logger.getRootLogger().addAppender(slowDownAppender); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + responseReceived.set(0); + respondentSendError.set(0); + forwardFailures.set(0); + sendsWithNoConsumers.set(0); + networkConnectors.clear(); + advisoryConsumerConnections.clear(); + consumerDemandExists = new CountDownLatch(1); + createBroker(new URI("broker:(tcp://localhost:0)/" + BROKER_A + "?persistent=false&useJmx=false")).setDedicatedTaskRunner(false); + createBroker(new URI("broker:(tcp://localhost:0)/" + BROKER_B + "?persistent=false&useJmx=false")).setDedicatedTaskRunner(false); + createBroker(new URI("broker:(tcp://localhost:0)/" + BROKER_C + "?persistent=false&useJmx=false")).setDedicatedTaskRunner(false); + + PolicyMap map = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setSendAdvisoryIfNoConsumers(true); + DeadLetterStrategy deadletterStrategy = new SharedDeadLetterStrategy(); + deadletterStrategy.setProcessNonPersistent(true); + defaultEntry.setDeadLetterStrategy(deadletterStrategy); + defaultEntry.setDispatchPolicy(new PriorityDispatchPolicy()); + map.put(new ActiveMQTempTopic(">"), defaultEntry); + + for (BrokerItem item : brokers.values()) { + item.broker.setDestinationPolicy(map); + } + } + + @Override + protected void tearDown() throws Exception { + if (slowDownAppender != null) { + org.apache.log4j.Logger.getRootLogger().removeAppender(slowDownAppender); + } + for (Connection connection : advisoryConsumerConnections) { + connection.close(); + } + super.tearDown(); + } + + protected NetworkConnector bridgeBrokers(String localBrokerName, String remoteBrokerName, boolean dynamicOnly, int networkTTL) throws Exception { + NetworkConnector connector = super.bridgeBrokers(localBrokerName, remoteBrokerName, dynamicOnly, networkTTL, true); + connector.setBridgeTempDestinations(true); + connector.setAdvisoryForFailedForward(true); + connector.setDuplex(useDuplex); + connector.setAlwaysSyncSend(true); + networkConnectors.add(connector); + return connector; + } + + abstract class MessageClient { + protected Connection connection; + protected Session session; + protected MessageConsumer consumer; + protected MessageProducer producer; + protected Random random; + protected int timeToSleep; + + // set up the connection and session + public MessageClient(ActiveMQConnectionFactory factory, int timeToSleep) throws Exception { + this.connection = factory.createConnection(); + this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + this.timeToSleep = timeToSleep; + this.random = new Random(System.currentTimeMillis()); + preInit(); + initProducer(); + initConsumer(); + this.connection.start(); + } + + protected void preInit() throws JMSException { + + } + + abstract protected void initProducer() throws JMSException; + + abstract protected void initConsumer() throws JMSException; + } + + class MessageSender extends MessageClient implements Runnable { + + + protected Destination tempDest; + + public MessageSender(ActiveMQConnectionFactory factory) throws Exception { + super(factory, RANDOM_SLEEP_FOR_SENDER_MS); + } + + @Override + public void run() { + // create a message + try { + TextMessage message = session.createTextMessage("request: message #" + messageCount.getAndIncrement()); + message.setJMSReplyTo(tempDest); + producer.send(message); + LOG.info("SENDER: Message [" + message.getText() + "] has been sent."); + + Message incomingMessage = consumer.receive(timeToSleep); + if (incomingMessage instanceof TextMessage) { + try { + LOG.info("SENDER: Got a response from echo service!" + ((TextMessage) incomingMessage).getText()); + responseReceived.incrementAndGet(); + } catch (JMSException e) { + LOG.error("SENDER: might want to see why i'm getting non-text messages..." + incomingMessage, e); + } + } else { + LOG.info("SENDER: Did not get a response this time"); + } + + + } catch (JMSException e) { + LOG.error("SENDER: Could not complete message sending properly: " + e.getMessage()); + } finally { + try { + producer.close(); + consumer.close(); + session.close(); + connection.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + + @Override + protected void preInit() throws JMSException { + this.tempDest = session.createTemporaryTopic(); + + } + + @Override + protected void initProducer() throws JMSException { + this.producer = session.createProducer(new ActiveMQQueue(QUEUE_NAME)); + } + + @Override + protected void initConsumer() throws JMSException { + this.consumer = session.createConsumer(tempDest); + LOG.info("consumer for: " + tempDest + ", " + consumer); + + } + + } + + class EchoRespondent extends MessageClient implements Runnable { + + public EchoRespondent(ActiveMQConnectionFactory factory) throws Exception { + super(factory, RANDOM_SLEEP_FOR_RESPONDENT_MS); + } + + @Override + public void run() { + try { + LOG.info("RESPONDENT LISTENING"); + while (!shutdown.get()) { + Message incomingMessage = consumer.receive(1000); + if (incomingMessage instanceof TextMessage) { + ActiveMQTextMessage textMessage = (ActiveMQTextMessage) incomingMessage; + try { + LOG.info("RESPONDENT: Received a message: [" + textMessage.getText() + "]" + Arrays.asList(textMessage.getBrokerPath())); + Message message = session.createTextMessage("reply: " + textMessage.getText()); + Destination replyTo = incomingMessage.getJMSReplyTo(); + TimeUnit.MILLISECONDS.sleep(timeToSleep); + consumerDemandExists.await(5, TimeUnit.SECONDS); + try { + producer.send(replyTo, message); + LOG.info("RESPONDENT: sent reply:" + message.getJMSMessageID() + " back to: " + replyTo); + } catch (JMSException e) { + LOG.error("RESPONDENT: could not send reply message: " + e.getLocalizedMessage(), e); + respondentSendError.incrementAndGet(); + } + } catch (JMSException e) { + LOG.error("RESPONDENT: could not create the reply message: " + e.getLocalizedMessage(), e); + } catch (InterruptedException e) { + LOG.info("RESPONDENT could not generate a random number"); + } + } + } + } catch (JMSException e) { + LOG.info("RESPONDENT: Could not set the message listener on the respondent"); + } + } + + @Override + protected void initProducer() throws JMSException { + this.producer = session.createProducer(null); + // so that we can get an advisory on sending with no consumers + this.producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + } + + @Override + protected void initConsumer() throws JMSException { + this.consumer = session.createConsumer(new ActiveMQQueue(QUEUE_NAME)); + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyToTopicViaThreeNetworkHopsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyToTopicViaThreeNetworkHopsTest.java new file mode 100644 index 0000000000..0c042f482e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/RequestReplyToTopicViaThreeNetworkHopsTest.java @@ -0,0 +1,977 @@ +/** + * 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.usecases; + +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQSession; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; + +public class RequestReplyToTopicViaThreeNetworkHopsTest { + protected static final int CONCURRENT_CLIENT_COUNT = 5; + protected static final int CONCURRENT_SERVER_COUNT = 5; + protected static final int TOTAL_CLIENT_ITER = 10; + + protected static int Next_broker_num = 0; + protected EmbeddedTcpBroker edge1; + protected EmbeddedTcpBroker edge2; + protected EmbeddedTcpBroker core1; + protected EmbeddedTcpBroker core2; + + protected boolean testError = false; + protected boolean fatalTestError = false; + + protected int echoResponseFill = 0; // Number of "filler" response messages per request + + protected static Log LOG; + public boolean duplex = true; + + static { + LOG = LogFactory.getLog(RequestReplyToTopicViaThreeNetworkHopsTest.class); + } + + public RequestReplyToTopicViaThreeNetworkHopsTest() throws Exception { + edge1 = new EmbeddedTcpBroker("edge", 1); + edge2 = new EmbeddedTcpBroker("edge", 2); + core1 = new EmbeddedTcpBroker("core", 1); + core2 = new EmbeddedTcpBroker("core", 2); + + // duplex is necessary to serialise sends with consumer/destination creation + edge1.coreConnectTo(core1, duplex); + edge2.coreConnectTo(core2, duplex); + core1.coreConnectTo(core2, duplex); + } + + public void logMessage(String msg) { + System.out.println(msg); + System.out.flush(); + } + + public void testMessages(Session sess, MessageProducer req_prod, Destination resp_dest, int num_msg) throws Exception { + MessageConsumer resp_cons; + TextMessage msg; + MessageClient cons_client; + int cur; + int tot_expected; + + resp_cons = sess.createConsumer(resp_dest); + + cons_client = new MessageClient(resp_cons, num_msg); + cons_client.start(); + + cur = 0; + while ((cur < num_msg) && (!fatalTestError)) { + msg = sess.createTextMessage("MSG AAAA " + cur); + msg.setIntProperty("SEQ", 100 + cur); + msg.setStringProperty("TEST", "TOPO"); + msg.setJMSReplyTo(resp_dest); + + if (cur == (num_msg - 1)) + msg.setBooleanProperty("end-of-response", true); + + sendWithRetryOnDeletedDest(req_prod, msg); + LOG.debug("Sent:" + msg); + + cur++; + } + + // + // Give the consumer some time to receive the response. + // + cons_client.waitShutdown(5000); + + // + // Now shutdown the consumer if it's still running. + // + if (cons_client.shutdown()) + LOG.debug("Consumer client shutdown complete"); + else + LOG.debug("Consumer client shutdown incomplete!!!"); + + // + // Check that the correct number of messages was received. + // + tot_expected = num_msg * (echoResponseFill + 1); + + if (cons_client.getNumMsgReceived() == tot_expected) { + LOG.debug("Have " + tot_expected + " messages, as-expected"); + } else { + testError = true; + + if (cons_client.getNumMsgReceived() == 0) + fatalTestError = true; + + LOG.error("Have " + cons_client.getNumMsgReceived() + " messages; expected " + tot_expected + " on destination " + resp_dest); + } + + resp_cons.close(); + } + + protected void sendWithRetryOnDeletedDest(MessageProducer prod, Message msg) throws JMSException { + try { + if (LOG.isDebugEnabled()) + LOG.debug("SENDING REQUEST message " + msg); + + prod.send(msg); + } catch (JMSException jms_exc) { + System.out.println("AAA: " + jms_exc.getMessage()); + throw jms_exc; + } + } + + /** + * Test one destination between the given "producer broker" and "consumer broker" specified. + */ + public void testOneDest(Connection conn, Session sess, Destination cons_dest, int num_msg) throws Exception { + Destination prod_dest; + MessageProducer msg_prod; + + // + // Create the Producer to the echo request Queue + // + LOG.trace("Creating echo queue and producer"); + prod_dest = sess.createQueue("echo"); + msg_prod = sess.createProducer(prod_dest); + + // + // Pass messages around. + // + testMessages(sess, msg_prod, cons_dest, num_msg); + + msg_prod.close(); + } + + /** + * TEST TEMPORARY TOPICS + */ + public void testTempTopic(String prod_broker_url, String cons_broker_url) throws Exception { + Connection conn; + Session sess; + Destination cons_dest; + int num_msg; + + num_msg = 5; + + LOG.debug("TESTING TEMP TOPICS " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + // + // Connect to the bus. + // + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // + // Create the destination on which messages are being tested. + // + LOG.trace("Creating destination"); + cons_dest = sess.createTemporaryTopic(); + + testOneDest(conn, sess, cons_dest, num_msg); + + // + // Cleanup + // + sess.close(); + conn.close(); + } + + /** + * TEST TOPICS + */ + public void testTopic(String prod_broker_url, String cons_broker_url) throws Exception { + int num_msg; + + Connection conn; + Session sess; + String topic_name; + + Destination cons_dest; + + num_msg = 5; + + LOG.info("TESTING TOPICS " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // + // Create the destination on which messages are being tested. + // + topic_name = "topotest2.perm.topic"; + LOG.trace("Removing existing Topic"); + removeTopic(conn, topic_name); + LOG.trace("Creating Topic, " + topic_name); + cons_dest = sess.createTopic(topic_name); + + testOneDest(conn, sess, cons_dest, num_msg); + + // + // Cleanup + // + removeTopic(conn, topic_name); + sess.close(); + conn.close(); + } + + /** + * TEST TEMPORARY QUEUES + */ + public void testTempQueue(String prod_broker_url, String cons_broker_url) throws Exception { + int num_msg; + + Connection conn; + Session sess; + + Destination cons_dest; + + num_msg = 5; + + LOG.info("TESTING TEMP QUEUES " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + // + // Connect to the bus. + // + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // + // Create the destination on which messages are being tested. + // + LOG.trace("Creating destination"); + cons_dest = sess.createTemporaryQueue(); + + testOneDest(conn, sess, cons_dest, num_msg); + + // + // Cleanup + // + sess.close(); + conn.close(); + } + + /** + * TEST QUEUES + */ + public void testQueue(String prod_broker_url, String cons_broker_url) throws Exception { + int num_msg; + + Connection conn; + Session sess; + String queue_name; + + Destination cons_dest; + + num_msg = 5; + + LOG.info("TESTING QUEUES " + prod_broker_url + " -> " + cons_broker_url + " (" + num_msg + " messages)"); + + conn = createConnection(cons_broker_url); + conn.start(); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // + // Create the destination on which messages are being tested. + // + queue_name = "topotest2.perm.queue"; + LOG.trace("Removing existing Queue"); + removeQueue(conn, queue_name); + LOG.trace("Creating Queue, " + queue_name); + cons_dest = sess.createQueue(queue_name); + + testOneDest(conn, sess, cons_dest, num_msg); + + removeQueue(conn, queue_name); + sess.close(); + conn.close(); + } + + @Test + public void runWithTempTopicReplyTo() throws Exception { + EchoService echo_svc; + TopicTrafficGenerator traffic_gen; + Thread start1; + Thread start2; + Thread start3; + Thread start4; + ThreadPoolExecutor clientExecPool; + final CountDownLatch clientCompletionLatch; + int iter; + + fatalTestError = false; + testError = false; + + // + // Execute up to 20 clients at a time to simulate that load. + // + + clientExecPool = new ThreadPoolExecutor(CONCURRENT_CLIENT_COUNT, CONCURRENT_CLIENT_COUNT, 0, TimeUnit.SECONDS, new ArrayBlockingQueue(10000)); + clientCompletionLatch = new CountDownLatch(TOTAL_CLIENT_ITER); + + // Use threads to avoid startup deadlock since the first broker started waits until + // it knows the name of the remote broker before finishing its startup, which means + // the remote must already be running. + + start1 = new Thread() { + @Override + public void run() { + try { + edge1.start(); + } catch (Exception ex) { + LOG.error(null, ex); + } + } + }; + + start2 = new Thread() { + @Override + public void run() { + try { + edge2.start(); + } catch (Exception ex) { + LOG.error(null, ex); + } + } + }; + + start3 = new Thread() { + @Override + public void run() { + try { + core1.start(); + } catch (Exception ex) { + LOG.error(null, ex); + } + } + }; + + start4 = new Thread() { + @Override + public void run() { + try { + core2.start(); + } catch (Exception ex) { + LOG.error(null, ex); + } + } + }; + + start1.start(); + start2.start(); + start3.start(); + start4.start(); + + start1.join(); + start2.join(); + start3.join(); + start4.join(); + + traffic_gen = new TopicTrafficGenerator(edge1.getConnectionUrl(), edge2.getConnectionUrl()); + traffic_gen.start(); + + // + // Now start the echo service with that queue. + // + echo_svc = new EchoService("echo", edge1.getConnectionUrl()); + echo_svc.start(); + + // + // Run the tests on Temp Topics. + // + + LOG.info("** STARTING TEMP TOPIC TESTS"); + iter = 0; + while ((iter < TOTAL_CLIENT_ITER) && (!fatalTestError)) { + clientExecPool.execute(new Runnable() { + @Override + public void run() { + try { + RequestReplyToTopicViaThreeNetworkHopsTest.this.testTempTopic(edge1.getConnectionUrl(), edge2.getConnectionUrl()); + } catch (Exception exc) { + LOG.error("test exception", exc); + fatalTestError = true; + testError = true; + } + + clientCompletionLatch.countDown(); + } + }); + + iter++; + } + + boolean allDoneOnTime = clientCompletionLatch.await(20, TimeUnit.MINUTES); + + LOG.info("** FINISHED TEMP TOPIC TESTS AFTER " + iter + " ITERATIONS, testError:" + testError + ", fatal: " + fatalTestError + ", onTime:" + + allDoneOnTime); + + Thread.sleep(100); + + echo_svc.shutdown(); + traffic_gen.shutdown(); + + shutdown(); + + assertTrue("test completed in time", allDoneOnTime); + assertTrue("no errors", !testError); + } + + public void shutdown() throws Exception { + edge1.stop(); + edge2.stop(); + core1.stop(); + core2.stop(); + } + + protected Connection createConnection(String url) throws Exception { + return org.apache.activemq.ActiveMQConnection.makeConnection(url); + } + + protected static void removeQueue(Connection conn, String dest_name) throws java.lang.Exception { + org.apache.activemq.command.ActiveMQDestination dest; + + if (conn instanceof org.apache.activemq.ActiveMQConnection) { + dest = org.apache.activemq.command.ActiveMQDestination.createDestination(dest_name, org.apache.activemq.command.ActiveMQDestination.QUEUE_TYPE); + ((org.apache.activemq.ActiveMQConnection) conn).destroyDestination(dest); + } + } + + protected static void removeTopic(Connection conn, String dest_name) throws java.lang.Exception { + org.apache.activemq.command.ActiveMQDestination dest; + + if (conn instanceof org.apache.activemq.ActiveMQConnection) { + dest = org.apache.activemq.command.ActiveMQDestination.createDestination(dest_name, org.apache.activemq.command.ActiveMQDestination.TOPIC_TYPE); + ((org.apache.activemq.ActiveMQConnection) conn).destroyDestination(dest); + } + } + + public static String fmtMsgInfo(Message msg) throws Exception { + StringBuilder msg_desc; + String prop; + Enumeration prop_enum; + + msg_desc = new StringBuilder(); + msg_desc = new StringBuilder(); + + if (msg instanceof TextMessage) { + msg_desc.append(((TextMessage) msg).getText()); + } else { + msg_desc.append("["); + msg_desc.append(msg.getClass().getName()); + msg_desc.append("]"); + } + + prop_enum = msg.getPropertyNames(); + while (prop_enum.hasMoreElements()) { + prop = (String) prop_enum.nextElement(); + msg_desc.append("; "); + msg_desc.append(prop); + msg_desc.append("="); + msg_desc.append(msg.getStringProperty(prop)); + } + + return msg_desc.toString(); + } + + protected class EmbeddedTcpBroker { + protected BrokerService brokerSvc; + protected int brokerNum; + protected String brokerName; + protected String brokerId; + protected int port; + protected String tcpUrl; + protected String fullUrl; + + public EmbeddedTcpBroker(String name, int number) throws Exception { + brokerSvc = new BrokerService(); + + synchronized (this.getClass()) { + brokerNum = Next_broker_num; + Next_broker_num++; + } + + brokerName = name + number; + brokerId = brokerName; + + brokerSvc.setBrokerName(brokerName); + brokerSvc.setBrokerId(brokerId); + + brokerSvc.setPersistent(false); + brokerSvc.setUseJmx(false); + + port = 60000 + (brokerNum * 10); + + tcpUrl = "tcp://127.0.0.1:" + Integer.toString(port); + fullUrl = tcpUrl + "?jms.watchTopicAdvisories=false"; + + brokerSvc.addConnector(tcpUrl); + } + + public Connection createConnection() throws URISyntaxException, JMSException { + Connection result; + + result = org.apache.activemq.ActiveMQConnection.makeConnection(this.fullUrl); + + return result; + } + + public String getConnectionUrl() { + return this.fullUrl; + } + + public void coreConnectTo(EmbeddedTcpBroker other, boolean duplex_f) throws Exception { + this.makeConnectionTo(other, duplex_f, true); + this.makeConnectionTo(other, duplex_f, false); + if (!duplex_f) { + other.makeConnectionTo(this, duplex_f, true); + other.makeConnectionTo(this, duplex_f, false); + } + } + + public void start() throws Exception { + brokerSvc.start(); + brokerSvc.waitUntilStarted(); + } + + public void stop() throws Exception { + brokerSvc.stop(); + } + + protected void makeConnectionTo(EmbeddedTcpBroker other, boolean duplex_f, boolean queue_f) throws Exception { + NetworkConnector nw_conn; + String prefix; + ActiveMQDestination excl_dest; + ArrayList excludes; + + nw_conn = new DiscoveryNetworkConnector(new URI("static:(" + other.tcpUrl + ")")); + nw_conn.setDuplex(duplex_f); + + if (queue_f) + nw_conn.setConduitSubscriptions(false); + else + nw_conn.setConduitSubscriptions(true); + + nw_conn.setNetworkTTL(3); + nw_conn.setSuppressDuplicateQueueSubscriptions(true); + nw_conn.setDecreaseNetworkConsumerPriority(true); + nw_conn.setBridgeTempDestinations(queue_f); + + if (queue_f) { + prefix = "queue"; + excl_dest = ActiveMQDestination.createDestination(">", ActiveMQDestination.TOPIC_TYPE); + } else { + prefix = "topic"; + excl_dest = ActiveMQDestination.createDestination(">", ActiveMQDestination.QUEUE_TYPE); + } + + excludes = new ArrayList(); + excludes.add(excl_dest); + nw_conn.setExcludedDestinations(excludes); + + if (duplex_f) + nw_conn.setName(this.brokerId + "<-" + prefix + "->" + other.brokerId); + else + nw_conn.setName(this.brokerId + "-" + prefix + "->" + other.brokerId); + + brokerSvc.addNetworkConnector(nw_conn); + } + } + + protected class MessageClient extends java.lang.Thread { + protected MessageConsumer msgCons; + protected boolean shutdownInd; + protected int expectedCount; + protected int lastSeq = 0; + protected int msgCount = 0; + protected boolean haveFirstSeq; + protected CountDownLatch shutdownLatch; + + public MessageClient(MessageConsumer cons, int num_to_expect) { + msgCons = cons; + expectedCount = (num_to_expect * (echoResponseFill + 1)); + shutdownLatch = new CountDownLatch(1); + } + + @Override + public void run() { + CountDownLatch latch; + + try { + synchronized (this) { + latch = shutdownLatch; + } + + shutdownInd = false; + processMessages(); + + latch.countDown(); + } catch (Exception exc) { + LOG.error("message client error", exc); + } + } + + public void waitShutdown(long timeout) { + CountDownLatch latch; + + try { + synchronized (this) { + latch = shutdownLatch; + } + + if (latch != null) + latch.await(timeout, TimeUnit.MILLISECONDS); + else + LOG.info("echo client shutdown: client does not appear to be active"); + } catch (InterruptedException int_exc) { + LOG.warn("wait for message client shutdown interrupted", int_exc); + } + } + + public boolean shutdown() { + boolean down_ind; + + if (!shutdownInd) { + shutdownInd = true; + } + + waitShutdown(200); + + synchronized (this) { + if ((shutdownLatch == null) || (shutdownLatch.getCount() == 0)) + down_ind = true; + else + down_ind = false; + } + + return down_ind; + } + + public int getNumMsgReceived() { + return msgCount; + } + + protected void processMessages() throws Exception { + Message in_msg; + + haveFirstSeq = false; + + // + // Stop at shutdown time or after any test error is detected. + // + + while ((!shutdownInd) && (!fatalTestError)) { + in_msg = msgCons.receive(100); + + if (in_msg != null) { + msgCount++; + checkMessage(in_msg); + } + } + + msgCons.close(); + } + + protected void checkMessage(Message in_msg) throws Exception { + int seq; + + LOG.debug("received message " + fmtMsgInfo(in_msg) + " from " + in_msg.getJMSDestination()); + + // + // Only check messages with a sequence number. + // + + if (in_msg.propertyExists("SEQ")) { + seq = in_msg.getIntProperty("SEQ"); + + if ((haveFirstSeq) && (seq != (lastSeq + 1))) { + LOG.error("***ERROR*** incorrect sequence number; expected " + Integer.toString(lastSeq + 1) + " but have " + Integer.toString(seq)); + + testError = true; + } + + lastSeq = seq; + + if (msgCount > expectedCount) { + LOG.error("*** have more messages than expected; have " + msgCount + "; expect " + expectedCount); + + testError = true; + } + } + + if (in_msg.propertyExists("end-of-response")) { + LOG.trace("received end-of-response message"); + } + } + } + + /** + * + */ + protected class EchoService extends java.lang.Thread { + protected String destName; + protected Connection jmsConn; + protected Session sess; + protected MessageConsumer msg_cons; + protected boolean Shutdown_ind; + + protected Destination req_dest; + + protected CountDownLatch waitShutdown; + + protected ThreadPoolExecutor processorPool; + + public EchoService(String dest, Connection broker_conn) throws Exception { + destName = dest; + jmsConn = broker_conn; + + Shutdown_ind = false; + + sess = jmsConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + req_dest = sess.createQueue(destName); + msg_cons = sess.createConsumer(req_dest); + + jmsConn.start(); + + waitShutdown = new CountDownLatch(1); + + processorPool = new ThreadPoolExecutor(CONCURRENT_SERVER_COUNT, CONCURRENT_SERVER_COUNT, 0, TimeUnit.SECONDS, new ArrayBlockingQueue( + 10000)); + } + + public EchoService(String dest, String broker_url) throws Exception { + this(dest, ActiveMQConnection.makeConnection(broker_url)); + } + + @Override + public void run() { + Message req; + + try { + LOG.info("STARTING ECHO SERVICE"); + + while (!Shutdown_ind) { + req = msg_cons.receive(100); + if (req != null) { + processorPool.execute(new EchoRequestProcessor(sess, req)); + } + } + } catch (Exception ex) { + LOG.error("error processing echo service requests", ex); + } finally { + LOG.info("shutting down test echo service"); + + try { + jmsConn.stop(); + } catch (javax.jms.JMSException jms_exc) { + LOG.warn("error on shutting down JMS connection", jms_exc); + } + + synchronized (this) { + waitShutdown.countDown(); + } + } + } + + /** + * Shut down the service, waiting up to 3 seconds for the service to terminate. + */ + public void shutdown() { + CountDownLatch wait_l; + + synchronized (this) { + wait_l = waitShutdown; + } + + Shutdown_ind = true; + + try { + if (wait_l != null) { + if (wait_l.await(3000, TimeUnit.MILLISECONDS)) + LOG.info("echo service shutdown complete"); + else + LOG.warn("timeout waiting for echo service shutdown"); + } else { + LOG.info("echo service shutdown: service does not appear to be active"); + } + } catch (InterruptedException int_exc) { + LOG.warn("interrupted while waiting for echo service shutdown"); + } + } + } + + /** + * + */ + protected class EchoRequestProcessor implements Runnable { + protected Session session; + + protected Destination resp_dest; + protected MessageProducer msg_prod; + + protected Message request; + + public EchoRequestProcessor(Session sess, Message req) throws Exception { + this.session = sess; + this.request = req; + + this.resp_dest = req.getJMSReplyTo(); + + if (resp_dest == null) { + throw new Exception("invalid request: no reply-to destination given"); + } + + this.msg_prod = session.createProducer(this.resp_dest); + } + + @Override + public void run() { + try { + this.processRequest(this.request); + } catch (Exception ex) { + LOG.error("Failed to process request", ex); + } + } + + /** + * Process one request for the Echo Service. + */ + protected void processRequest(Message req) throws Exception { + if (LOG.isDebugEnabled()) + LOG.debug("ECHO request message " + req.toString()); + + resp_dest = req.getJMSReplyTo(); + if (resp_dest != null) { + msg_prod = session.createProducer(resp_dest); + + LOG.debug("SENDING ECHO RESPONSE to:" + resp_dest); + + msg_prod.send(req); + + LOG.debug((((ActiveMQSession) session).getConnection()).getBrokerName() + " SENT ECHO RESPONSE to " + resp_dest); + + msg_prod.close(); + msg_prod = null; + } else { + LOG.warn("invalid request: no reply-to destination given"); + } + } + } + + protected class TopicTrafficGenerator extends java.lang.Thread { + protected Connection conn1; + protected Connection conn2; + protected Session sess1; + protected Session sess2; + protected Destination dest; + protected MessageProducer prod; + protected MessageConsumer cons; + protected boolean Shutdown_ind; + protected int send_count; + + public TopicTrafficGenerator(String url1, String url2) throws Exception { + conn1 = createConnection(url1); + conn2 = createConnection(url2); + + sess1 = conn1.createSession(false, Session.AUTO_ACKNOWLEDGE); + sess2 = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE); + + conn1.start(); + conn2.start(); + + dest = sess1.createTopic("traffic"); + prod = sess1.createProducer(dest); + + dest = sess2.createTopic("traffic"); + cons = sess2.createConsumer(dest); + } + + public void shutdown() { + Shutdown_ind = true; + } + + @Override + public void run() { + Message msg; + + try { + LOG.info("Starting Topic Traffic Generator"); + + while (!Shutdown_ind) { + msg = sess1.createTextMessage("TRAFFIC"); + + prod.send(msg); + + send_count++; + + // + // Time out the receipt; early messages may not make it. + // + + msg = cons.receive(250); + } + } catch (JMSException jms_exc) { + LOG.warn("traffic generator failed on jms exception", jms_exc); + } finally { + LOG.info("Shutdown of Topic Traffic Generator; send count = " + send_count); + + if (conn1 != null) { + try { + conn1.stop(); + } catch (JMSException jms_exc) { + LOG.warn("failed to shutdown connection", jms_exc); + } + } + + if (conn2 != null) { + try { + conn2.stop(); + } catch (JMSException jms_exc) { + LOG.warn("failed to shutdown connection", jms_exc); + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SingleBrokerVirtualDestinationsWithWildcardLevelDBTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SingleBrokerVirtualDestinationsWithWildcardLevelDBTest.java new file mode 100644 index 0000000000..543f83fc35 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SingleBrokerVirtualDestinationsWithWildcardLevelDBTest.java @@ -0,0 +1,44 @@ +/** + * 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.usecases; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.leveldb.LevelDBStore; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.MessageIdList; + +import javax.jms.MessageConsumer; +import java.io.File; +import java.io.IOException; +import java.net.URI; + +public class SingleBrokerVirtualDestinationsWithWildcardLevelDBTest extends SingleBrokerVirtualDestinationsWithWildcardTest { + + @Override + protected void configurePersistenceAdapter(BrokerService broker) throws IOException { + File dataFileDir = new File("target/test-amq-data/leveldb/" + broker.getBrokerName()); + LevelDBStore kaha = new LevelDBStore(); + kaha.setDirectory(dataFileDir); + broker.setPersistenceAdapter(kaha); + } + +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SingleBrokerVirtualDestinationsWithWildcardTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SingleBrokerVirtualDestinationsWithWildcardTest.java new file mode 100644 index 0000000000..f30cdb2d86 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SingleBrokerVirtualDestinationsWithWildcardTest.java @@ -0,0 +1,126 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.IOException; +import java.net.URI; + +import javax.jms.MessageConsumer; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.MessageIdList; + +public class SingleBrokerVirtualDestinationsWithWildcardTest extends JmsMultipleBrokersTestSupport { + + /** + * virtual destinations + */ + public void testVirtualDestinations() throws Exception { + startAllBrokers(); + + sendReceive("local.test", true, "Consumer.a.local.test", false, 1, 1); + sendReceive("global.test", true, "Consumer.a.global.test", false, 1, 1); + + destroyAllBrokers(); + } + + /** + * virtual destinations with wild-card subscriptions (without individual virtual queue) + */ + public void testVirtualDestinationsWithWildcardWithoutIndividualVirtualQueue() throws Exception { + startAllBrokers(); + + sendReceive("local.test.1", true, "Consumer.a.local.test.>", false, 1, 1); + sendReceive("global.test.1", true, "Consumer.a.global.test.>", false, 1, 1); + + destroyAllBrokers(); + } + + /** + * virtual destinations with wild-card subscriptions (with individual virtual queue) + */ + public void testVirtualDestinationsWithWildcardWithIndividualVirtualQueue() throws Exception { + startAllBrokers(); + + sendReceive("local.test.1", true, "Consumer.a.local.test.1", false, 1, 1); + sendReceive("local.test.1", true, "Consumer.a.local.test.>", false, 1, 1); + sendReceive("global.test.1", true, "Consumer.a.global.test.1", false, 1, 1); + sendReceive("global.test.1", true, "Consumer.a.global.test.>", false, 1, 1); + + destroyAllBrokers(); + } + + /** + * virtual destinations with wild-card subscriptions (wit virtual queue pre-created) + */ + public void testVirtualDestinationsWithWildcardWithVirtualQueuePreCreated() throws Exception { + startAllBrokers(); + + sendReceive("Consumer.a.local.test.>", false, "Consumer.a.local.test.>", false, 1, 1); + sendReceive("local.test.1", true, "Consumer.a.local.test.>", false, 1, 1); + sendReceive("Consumer.a.global.test.>", false, "Consumer.a.global.test.>", false, 1, 1); + sendReceive("global.test.1", true, "Consumer.a.global.test.>", false, 1, 1); + + destroyAllBrokers(); + } + + public void sendReceive(String dest1, boolean topic1, String dest2, boolean topic2, int send, int expected) throws Exception{ + MessageConsumer client = createConsumer("BrokerA", createDestination(dest2, topic2)); + Thread.sleep(1000); + sendMessages("BrokerA", createDestination(dest1, topic1), send); + MessageIdList msgs = getConsumerMessages("BrokerA", client); + msgs.setMaximumDuration(1000); + assertEquals(expected, msgs.getMessageCount()); + client.close(); + Thread.sleep(500); + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + String options = new String("?useJmx=false&deleteAllMessagesOnStartup=true"); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61616)/BrokerA" + options)); + } + + private BrokerService createAndConfigureBroker(URI uri) throws Exception { + BrokerService broker = createBroker(uri); + + configurePersistenceAdapter(broker); + + // make all topics virtual and consumers use the default prefix + VirtualDestinationInterceptor virtualDestinationInterceptor = new VirtualDestinationInterceptor(); + virtualDestinationInterceptor.setVirtualDestinations(new VirtualDestination[]{new VirtualTopic()}); + DestinationInterceptor[] destinationInterceptors = new DestinationInterceptor[]{virtualDestinationInterceptor}; + broker.setDestinationInterceptors(destinationInterceptors); + return broker; + } + + protected void configurePersistenceAdapter(BrokerService broker) throws IOException { + File dataFileDir = new File("target/test-amq-data/kahadb/" + broker.getBrokerName()); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(dataFileDir); + broker.setPersistenceAdapter(kaha); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopBrokerTest.java new file mode 100644 index 0000000000..728a2cca0b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopBrokerTest.java @@ -0,0 +1,78 @@ +/** + * 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.usecases; + +import java.net.URI; + +import javax.jms.JMSException; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; + +/** + * @author Oliver Belikan + * + */ +public class StartAndStopBrokerTest extends TestCase { + public void testStartupShutdown() throws Exception { + // This systemproperty is used if we dont want to + // have persistence messages as a default + System.setProperty("activemq.persistenceAdapter", + "org.apache.activemq.store.vm.VMPersistenceAdapter"); + + // configuration of container and all protocolls + BrokerService broker = createBroker(); + + // start a client + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:9100"); + factory.createConnection(); + + // stop activemq broker + broker.stop(); + + // start activemq broker again + broker = createBroker(); + + // start a client again + factory = new ActiveMQConnectionFactory("tcp://localhost:9100"); + factory.createConnection(); + + // stop activemq broker + broker.stop(); + + } + + protected BrokerService createBroker() throws JMSException { + BrokerService broker = null; + + try { + broker = BrokerFactory.createBroker(new URI("broker://()/localhost")); + broker.setBrokerName("DefaultBroker"); + broker.addConnector("tcp://localhost:9100"); + broker.setUseShutdownHook(false); + + broker.start(); + } catch (Exception e) { + e.printStackTrace(); + } + + return broker; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopClientAndBrokerDoesNotLeaveThreadsRunningTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopClientAndBrokerDoesNotLeaveThreadsRunningTest.java new file mode 100644 index 0000000000..164d6a82fa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopClientAndBrokerDoesNotLeaveThreadsRunningTest.java @@ -0,0 +1,93 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.spring.ConsumerBean; + +/** + * + * + */ +public class StartAndStopClientAndBrokerDoesNotLeaveThreadsRunningTest extends TestCase { + + public static interface Task { + void execute() throws Exception; + } + + public void setUp() throws Exception { + } + + public void testStartAndStopClientAndBrokerAndCheckNoThreadsAreLeft() throws Exception { + runTest(new Task() { + + public void execute() throws Exception { + BrokerService broker = new BrokerService(); + broker.setPersistent(false); + broker.start(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); + Connection connection = factory.createConnection(); + connection.start(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue destination = session.createQueue(getName()); + + // consumer + MessageConsumer consumer = session.createConsumer(destination); + ConsumerBean listener = new ConsumerBean(); + consumer.setMessageListener(listener); + + // producer + MessageProducer producer = session.createProducer(destination); + TextMessage message = session.createTextMessage("Hello World!"); + producer.send(message); + producer.close(); + + listener.assertMessagesArrived(1); + + consumer.close(); + session.close(); + connection.close(); + + broker.stop(); + } + }); + } + + public void runTest(Task task) throws Exception { + int before = Thread.currentThread().getThreadGroup().activeCount(); + + task.execute(); + + Thread.yield(); + // need to wait for slow servers + Thread.sleep(5000); + + int after = Thread.currentThread().getThreadGroup().activeCount(); + int diff = Math.abs(before - after); + assertTrue("Should be at most one more thread. Diff = " + diff, diff + 1 <= after); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StaticNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StaticNetworkTest.java new file mode 100644 index 0000000000..cba9c5c43c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/StaticNetworkTest.java @@ -0,0 +1,71 @@ +/** + * 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.usecases; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.MessageIdList; + +import javax.jms.MessageConsumer; +import java.net.URI; + +public class StaticNetworkTest extends JmsMultipleBrokersTestSupport { + + public void testStaticNetwork() throws Exception { + // Setup destination + ActiveMQDestination dest = createDestination("TEST", false); + ActiveMQDestination dest1 = createDestination("TEST1", false); + + NetworkConnector bridgeAB =bridgeBrokers("BrokerA", "BrokerB", true); + bridgeAB.addStaticallyIncludedDestination(dest); + bridgeAB.setStaticBridge(true); + + startAllBrokers(); + waitForBridgeFormation(); + + MessageConsumer consumer1 = createConsumer("BrokerB", dest); + MessageConsumer consumer2 = createConsumer("BrokerB", dest1); + + + Thread.sleep(1000); + + + sendMessages("BrokerA", dest, 1); + sendMessages("BrokerA", dest1, 1); + + MessageIdList msgs1 = getConsumerMessages("BrokerB", consumer1); + MessageIdList msgs2 = getConsumerMessages("BrokerB", consumer2); + + msgs1.waitForMessagesToArrive(1); + + Thread.sleep(1000); + + assertEquals(1, msgs1.getMessageCount()); + assertEquals(0, msgs2.getMessageCount()); + + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=false&useJmx=false")); + createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB?persistent=false&useJmx=false")); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SubscribeClosePublishThenConsumeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SubscribeClosePublishThenConsumeTest.java new file mode 100644 index 0000000000..38b9144bf7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/SubscribeClosePublishThenConsumeTest.java @@ -0,0 +1,111 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.test.TestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Paul Smith + * + */ +public class SubscribeClosePublishThenConsumeTest extends TestSupport { + private static final Logger LOG = LoggerFactory.getLogger(SubscribeClosePublishThenConsumeTest.class); + + public void testDurableTopic() throws Exception { + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://locahost"); + + String topicName = "TestTopic"; + String clientID = getName(); + String subscriberName = "MySubscriber:" + System.currentTimeMillis(); + + Connection connection = connectionFactory.createConnection(); + connection.setClientID(clientID); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic(topicName); + + // this should register a durable subscriber, we then close it to + // test that we get messages from the producer later on + TopicSubscriber subscriber = session.createDurableSubscriber(topic, subscriberName); + connection.start(); + + topic = null; + subscriber.close(); + subscriber = null; + session.close(); + session = null; + + // Create the new connection before closing to avoid the broker shutting + // down. + // now create a new Connection, Session & Producer, send some messages & + // then close + Connection t = connectionFactory.createConnection(); + connection.close(); + connection = t; + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = session.createTopic(topicName); + MessageProducer producer = session.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + TextMessage textMessage = session.createTextMessage("Hello World"); + producer.send(textMessage); + textMessage = null; + + topic = null; + session.close(); + session = null; + + // Now (re)register the Durable subscriber, setup a listener and wait + // for messages that should + // have been published by the previous producer + t = connectionFactory.createConnection(); + connection.close(); + connection = t; + + connection.setClientID(clientID); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = session.createTopic(topicName); + + subscriber = session.createDurableSubscriber(topic, subscriberName); + connection.start(); + + LOG.info("Started connection - now about to try receive the textMessage"); + + long time = System.currentTimeMillis(); + Message message = subscriber.receive(15000L); + long elapsed = System.currentTimeMillis() - time; + + LOG.info("Waited for: " + elapsed + " millis"); + + assertNotNull("Should have received the message we published by now", message); + assertTrue("should be text textMessage", message instanceof TextMessage); + textMessage = (TextMessage)message; + assertEquals("Hello World", textMessage.getText()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TempTopicProducerFlowControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TempTopicProducerFlowControlTest.java new file mode 100644 index 0000000000..ca8b697bba --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TempTopicProducerFlowControlTest.java @@ -0,0 +1,43 @@ +/** + * 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.usecases; + +import javax.jms.Destination; +import javax.jms.Session; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; + +public class TempTopicProducerFlowControlTest extends TopicProducerFlowControlTest { + + @Override + protected void setDestinationPolicy(BrokerService broker, PolicyMap pm) { + PolicyEntry tpe = new PolicyEntry(); + tpe.setTempTopic(true); + tpe.setMemoryLimit(destinationMemLimit); + tpe.setProducerFlowControl(true); + tpe.setAdvisoryWhenFull(true); + pm.setDefaultEntry(tpe); + + broker.setDestinationPolicy(pm); + } + + @Override + protected Destination createDestination(Session session) throws Exception { + return session.createTemporaryTopic(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TestBrokerConnectionDuplexExcludedDestinations.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TestBrokerConnectionDuplexExcludedDestinations.java new file mode 100644 index 0000000000..2d3b64ceb1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TestBrokerConnectionDuplexExcludedDestinations.java @@ -0,0 +1,171 @@ +/** + * 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.usecases; + +import java.net.URI; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; + +public class TestBrokerConnectionDuplexExcludedDestinations extends TestCase { + + BrokerService receiverBroker; + BrokerService senderBroker; + + Connection hubConnection; + Session hubSession; + + Connection spokeConnection; + Session spokeSession; + + @Override + public void setUp() throws Exception { + // Hub broker + String configFileName = "org/apache/activemq/usecases/receiver-duplex.xml"; + URI uri = new URI("xbean:" + configFileName); + receiverBroker = BrokerFactory.createBroker(uri); + receiverBroker.setPersistent(false); + receiverBroker.setBrokerName("Hub"); + + // Spoke broker + configFileName = "org/apache/activemq/usecases/sender-duplex.xml"; + uri = new URI("xbean:" + configFileName); + senderBroker = BrokerFactory.createBroker(uri); + senderBroker.setPersistent(false); + senderBroker.setBrokerName("Spoke"); + + // Start both Hub and Spoke broker + receiverBroker.start(); + senderBroker.start(); + + // create hub session + ConnectionFactory cfHub = new ActiveMQConnectionFactory("tcp://localhost:62002"); + + hubConnection = cfHub.createConnection(); + hubConnection.start(); + hubSession = hubConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // create spoke session + ConnectionFactory cfSpoke = new ActiveMQConnectionFactory("tcp://localhost:62001"); + spokeConnection = cfSpoke.createConnection(); + spokeConnection.start(); + spokeSession = spokeConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + @Override + public void tearDown() throws Exception { + hubSession.close(); + hubConnection.stop(); + hubConnection.close(); + + spokeSession.close(); + spokeConnection.stop(); + spokeConnection.close(); + + senderBroker.stop(); + receiverBroker.stop(); + } + + public void testDuplexSendFromHubToSpoke() throws Exception { + + //create hub producer + MessageProducer hubProducer = hubSession.createProducer(null); + hubProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + hubProducer.setDisableMessageID(true); + hubProducer.setDisableMessageTimestamp(true); + + //create spoke producer + MessageProducer spokeProducer = hubSession.createProducer(null); + spokeProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + spokeProducer.setDisableMessageID(true); + spokeProducer.setDisableMessageTimestamp(true); + + Queue excludedQueueHub = hubSession.createQueue("exclude.test.foo"); + TextMessage excludedMsgHub = hubSession.createTextMessage(); + excludedMsgHub.setText(excludedQueueHub.toString()); + + Queue includedQueueHub = hubSession.createQueue("include.test.foo"); + + TextMessage includedMsgHub = hubSession.createTextMessage(); + includedMsgHub.setText(includedQueueHub.toString()); + + Queue alwaysIncludedQueueHub = hubSession.createQueue("always.include.test.foo"); + + TextMessage alwaysIncludedMsgHub = hubSession.createTextMessage(); + alwaysIncludedMsgHub.setText(alwaysIncludedQueueHub.toString()); + + // Sending from Hub queue + hubProducer.send(excludedQueueHub, excludedMsgHub); + hubProducer.send(includedQueueHub, includedMsgHub); + hubProducer.send(alwaysIncludedQueueHub, alwaysIncludedMsgHub); + + Queue excludedQueueSpoke = spokeSession.createQueue("exclude.test.foo"); + MessageConsumer excludedConsumerSpoke = spokeSession.createConsumer(excludedQueueSpoke); + + Thread.sleep(100); + + Queue includedQueueSpoke = spokeSession.createQueue("include.test.foo"); + MessageConsumer includedConsumerSpoke = spokeSession.createConsumer(includedQueueSpoke); + + Thread.sleep(100); + + Queue alwaysIncludedQueueSpoke = spokeSession.createQueue("always.include.test.foo"); + MessageConsumer alwaysIncludedConsumerSpoke = spokeSession.createConsumer(alwaysIncludedQueueHub); + + Thread.sleep(100); + TextMessage alwaysIncludedMsgSpoke = spokeSession.createTextMessage(); + alwaysIncludedMsgSpoke.setText(alwaysIncludedQueueSpoke.toString()); + spokeProducer.send(alwaysIncludedQueueSpoke, alwaysIncludedMsgSpoke); + + MessageConsumer alwaysIncludedConsumerHub = spokeSession.createConsumer(alwaysIncludedQueueHub); + assertNotNull(alwaysIncludedConsumerHub); + + // Receiving from excluded Spoke queue + Message msg = excludedConsumerSpoke.receive(200); + assertNull(msg); + + // Receiving from included Spoke queue + msg = includedConsumerSpoke.receive(200); + assertEquals(includedMsgHub, msg); + + // Receiving from included Spoke queue + msg = alwaysIncludedConsumerSpoke.receive(200); + assertEquals(alwaysIncludedMsgHub, msg); + + // we should be able to receive excluded queue message on Hub + MessageConsumer excludedConsumerHub = hubSession.createConsumer(excludedQueueHub); + msg = excludedConsumerHub.receive(200);; + assertEquals(excludedMsgHub, msg); + + hubProducer.close(); + excludedConsumerSpoke.close(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TestSupport.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TestSupport.java new file mode 100644 index 0000000000..4858870a07 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TestSupport.java @@ -0,0 +1,147 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +/** + * Useful base class for unit test cases + */ +public class TestSupport extends TestCase { + + protected ActiveMQConnectionFactory connectionFactory; + protected boolean topic = true; + + public TestSupport() { + super(); + } + + public TestSupport(String name) { + super(name); + } + + protected ActiveMQMessage createMessage() { + return new ActiveMQMessage(); + } + + protected Destination createDestination(String subject) { + if (topic) { + return new ActiveMQTopic(subject); + } else { + return new ActiveMQQueue(subject); + } + } + + protected void assertTextMessagesEqual(Message[] firstSet, Message[] secondSet) throws JMSException { + assertTextMessagesEqual("", firstSet, secondSet); + } + + /** + * @param messsage + * @param firstSet + * @param secondSet + */ + protected void assertTextMessagesEqual(String messsage, Message[] firstSet, Message[] secondSet) throws JMSException { + assertEquals("Message count does not match: " + messsage, firstSet.length, secondSet.length); + for (int i = 0; i < secondSet.length; i++) { + TextMessage m1 = (TextMessage)firstSet[i]; + TextMessage m2 = (TextMessage)secondSet[i]; + assertTextMessageEqual("Message " + (i + 1) + " did not match : ", m1, m2); + } + } + + protected void assertEquals(TextMessage m1, TextMessage m2) throws JMSException { + assertEquals("", m1, m2); + } + + /** + * @param message + * @param firstSet + * @param secondSet + */ + protected void assertTextMessageEqual(String message, TextMessage m1, TextMessage m2) throws JMSException { + assertFalse(message + ": expected {" + m1 + "}, but was {" + m2 + "}", m1 == null ^ m2 == null); + if (m1 == null) { + return; + } + assertEquals(message, m1.getText(), m2.getText()); + } + + protected void assertEquals(Message m1, Message m2) throws JMSException { + assertEquals("", m1, m2); + } + + /** + * @param message + * @param firstSet + * @param secondSet + */ + protected void assertEquals(String message, Message m1, Message m2) throws JMSException { + assertFalse(message + ": expected {" + m1 + "}, but was {" + m2 + "}", m1 == null ^ m2 == null); + if (m1 == null) { + return; + } + assertTrue(message + ": expected {" + m1 + "}, but was {" + m2 + "}", m1.getClass() == m2.getClass()); + if (m1 instanceof TextMessage) { + assertTextMessageEqual(message, (TextMessage)m1, (TextMessage)m2); + } else { + assertEquals(message, m1, m2); + } + } + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + return new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + } + + /** + * Factory method to create a new connection + */ + protected Connection createConnection() throws Exception { + return getConnectionFactory().createConnection(); + } + + public ActiveMQConnectionFactory getConnectionFactory() throws Exception { + if (connectionFactory == null) { + connectionFactory = createConnectionFactory(); + assertTrue("Should have created a connection factory!", connectionFactory != null); + } + return connectionFactory; + } + + protected String getConsumerSubject() { + return getSubject(); + } + + protected String getProducerSubject() { + return getSubject(); + } + + protected String getSubject() { + return getClass().getName() + "." + getName(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerQueueNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerQueueNetworkTest.java new file mode 100644 index 0000000000..2e91d4c9df --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerQueueNetworkTest.java @@ -0,0 +1,666 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerFilter; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Queue; +import org.apache.activemq.broker.region.RegionBroker; +import org.apache.activemq.broker.region.Subscription; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ConsumerInfo; +import org.apache.activemq.command.MessageDispatch; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ThreeBrokerQueueNetworkTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ThreeBrokerQueueNetworkTest.class); + protected static final int MESSAGE_COUNT = 100; + private static final long MAX_WAIT_MILLIS = 10000; + + interface Condition { + boolean isSatisified() throws Exception; + } + + /** + * BrokerA -> BrokerB -> BrokerC + */ + public void testABandBCbrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + bridgeBrokers("BrokerB", "BrokerC"); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientC = createConsumer("BrokerC", dest); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Let's try to wait for any messages. Should be none. + Thread.sleep(1000); + + // Get message count + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + assertEquals(0, msgsC.getMessageCount()); + } + + /** + * BrokerA <- BrokerB -> BrokerC + */ + public void testBAandBCbrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerB", "BrokerA"); + bridgeBrokers("BrokerB", "BrokerC"); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + Thread.sleep(2000); //et subscriptions get propagated + // Send messages + sendMessages("BrokerB", dest, MESSAGE_COUNT); + + // Let's try to wait for any messages. + Thread.sleep(1000); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + // Total received should be 100 + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount() + msgsC.getMessageCount()); + } + + /** + * BrokerA <- BrokerB -> BrokerC + */ + public void testBAandBCbrokerNetworkWithSelectorsSendFirst() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerB", "BrokerA", true, 1, false); + bridgeBrokers("BrokerB", "BrokerC", true, 1, false); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + + // Send messages for broker A + HashMap props = new HashMap(); + props.put("broker", "BROKER_A"); + sendMessages("BrokerB", dest, MESSAGE_COUNT, props); + + //Send messages for broker C + props.clear(); + props.put("broker", "BROKER_C"); + sendMessages("BrokerB", dest, MESSAGE_COUNT, props); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest, "broker = 'BROKER_A'"); + MessageConsumer clientC = createConsumer("BrokerC", dest, "broker = 'BROKER_C'"); + Thread.sleep(2000); //et subscriptions get propagated + + // Let's try to wait for any messages. + //Thread.sleep(1000); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + // Total received should be 100 + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT, msgsC.getMessageCount()); + } + + /** + * BrokerA <- BrokerB -> BrokerC + */ + public void testBAandBCbrokerNetworkWithSelectorsSubscribeFirst() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerB", "BrokerA", true, 1, false); + bridgeBrokers("BrokerB", "BrokerC", true, 1, false); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest, "broker = 'BROKER_A'"); + MessageConsumer clientC = createConsumer("BrokerC", dest, "broker = 'BROKER_C'"); + Thread.sleep(2000); //et subscriptions get propagated + + + // Send messages for broker A + HashMap props = new HashMap(); + props.put("broker", "BROKER_A"); + sendMessages("BrokerB", dest, MESSAGE_COUNT, props); + + //Send messages for broker C + props.clear(); + props.put("broker", "BROKER_C"); + sendMessages("BrokerB", dest, MESSAGE_COUNT, props); + + // Let's try to wait for any messages. + Thread.sleep(1000); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + // Total received should be 100 + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT, msgsC.getMessageCount()); + } + + /** + * BrokerA -> BrokerB <- BrokerC + */ + public void testABandCBbrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + bridgeBrokers("BrokerC", "BrokerB"); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientB = createConsumer("BrokerB", dest); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + + msgsB.waitForMessagesToArrive(MESSAGE_COUNT * 2); + + assertEquals(MESSAGE_COUNT * 2, msgsB.getMessageCount()); + } + + /** + * BrokerA <-> BrokerB <-> BrokerC + */ + public void testAllConnectedBrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + bridgeBrokers("BrokerB", "BrokerA"); + bridgeBrokers("BrokerB", "BrokerC"); + bridgeBrokers("BrokerC", "BrokerB"); + bridgeBrokers("BrokerA", "BrokerC"); + bridgeBrokers("BrokerC", "BrokerA"); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerB", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Let's try to wait for any messages. + Thread.sleep(1000); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + assertEquals(MESSAGE_COUNT * 3, msgsA.getMessageCount() + msgsB.getMessageCount() + msgsC.getMessageCount()); + } + + public void testAllConnectedUsingMulticast() throws Exception { + // Setup broker networks + bridgeAllBrokers(); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerB", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Let's try to wait for any messages. + Thread.sleep(1000); + + // Get message count + final MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + waitFor(new Condition() { + public boolean isSatisified() { + return msgsA.getMessageCount() == MESSAGE_COUNT; + } + }); + + assertEquals(MESSAGE_COUNT * 3, msgsA.getMessageCount() + msgsB.getMessageCount() + msgsC.getMessageCount()); + } + + // on slow machines some more waiting is required on account of slow advisories + private void waitFor(Condition condition) throws Exception { + final long expiry = System.currentTimeMillis() + MAX_WAIT_MILLIS; + while (!condition.isSatisified() && System.currentTimeMillis() < expiry) { + Thread.sleep(1000); + } + if (System.currentTimeMillis() >= expiry) { + LOG.error("expired while waiting for condition " + condition); + } + + } + + public void testAllConnectedUsingMulticastProducerConsumerOnA() throws Exception { + bridgeAllBrokers("default", 3, false); + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + int messageCount = 2000; + CountDownLatch messagesReceived = new CountDownLatch(messageCount); + MessageConsumer clientA = createConsumer("BrokerA", dest, messagesReceived); + + // Let's try to wait for advisory percolation. + Thread.sleep(1000); + + // Send messages + sendMessages("BrokerA", dest, messageCount); + + assertTrue(messagesReceived.await(30, TimeUnit.SECONDS)); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + assertEquals(messageCount, msgsA.getMessageCount()); + } + + public void testAllConnectedWithSpare() throws Exception { + bridgeAllBrokers("default", 3, false); + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + int messageCount = 2000; + CountDownLatch messagesReceived = new CountDownLatch(messageCount); + MessageConsumer clientA = createConsumer("BrokerA", dest, messagesReceived); + + // ensure advisory percolation. + Thread.sleep(2000); + + // Send messages + sendMessages("BrokerB", dest, messageCount); + + assertTrue("messaged received within time limit", messagesReceived.await(30, TimeUnit.SECONDS)); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + assertEquals(messageCount, msgsA.getMessageCount()); + } + + /* + * This test is disabled - as it fails with a fix for + * http://issues.apache.org/activemq/browse/AMQ-2530 - which highlights that + * For a Conduit bridge - local subscription Ids weren't removed in a ConduitBridge + * The test fails because on closing clientA - clientB correctly receives all the + * messages - ie. half dont get stuck on BrokerA - + */ + public void XtestMigrateConsumerStuckMessages() throws Exception { + boolean suppressQueueDuplicateSubscriptions = false; + bridgeAllBrokers("default", 3, suppressQueueDuplicateSubscriptions); + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + LOG.info("Consumer on A"); + MessageConsumer clientA = createConsumer("BrokerA", dest); + + // ensure advisors have percolated + Thread.sleep(2000); + + LOG.info("Consumer on B"); + int messageCount = 2000; + + // will only get half of the messages + CountDownLatch messagesReceived = new CountDownLatch(messageCount/2); + MessageConsumer clientB = createConsumer("BrokerB", dest, messagesReceived); + + // ensure advisors have percolated + Thread.sleep(2000); + + LOG.info("Close consumer on A"); + clientA.close(); + + // ensure advisors have percolated + Thread.sleep(2000); + + LOG.info("Send to B"); + sendMessages("BrokerB", dest, messageCount); + + // Let's try to wait for any messages. + assertTrue(messagesReceived.await(30, TimeUnit.SECONDS)); + + // Get message count + MessageIdList msgs = getConsumerMessages("BrokerB", clientB); + + // see will any more arrive + Thread.sleep(500); + assertEquals(messageCount/2, msgs.getMessageCount()); + + // pick up the stuck messages + messagesReceived = new CountDownLatch(messageCount/2); + clientA = createConsumer("BrokerA", dest, messagesReceived); + // Let's try to wait for any messages. + assertTrue(messagesReceived.await(30, TimeUnit.SECONDS)); + + msgs = getConsumerMessages("BrokerA", clientA); + assertEquals(messageCount/2, msgs.getMessageCount()); + } + + // use case: for maintenance, migrate consumers and producers from one + // node in the network to another so node can be replaced/updated + public void testMigrateConsumer() throws Exception { + boolean suppressQueueDuplicateSubscriptions = true; + boolean decreaseNetworkConsumerPriority = true; + bridgeAllBrokers("default", 3, suppressQueueDuplicateSubscriptions, decreaseNetworkConsumerPriority); + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + LOG.info("Consumer on A"); + MessageConsumer clientA = createConsumer("BrokerA", dest); + + // ensure advisors have percolated + Thread.sleep(2000); + + LOG.info("Consumer on B"); + int messageCount = 2000; + CountDownLatch messagesReceived = new CountDownLatch(messageCount); + MessageConsumer clientB = createConsumer("BrokerB", dest, messagesReceived); + + // make the consumer slow so that any network consumer has a chance, even + // if it has a lower priority + MessageIdList msgs = getConsumerMessages("BrokerB", clientB); + msgs.setProcessingDelay(10); + + // ensure advisors have percolated + Thread.sleep(2000); + + LOG.info("Close consumer on A"); + clientA.close(); + + // ensure advisors have percolated + Thread.sleep(2000); + + LOG.info("Send to B"); + sendMessages("BrokerB", dest, messageCount); + + // Let's try to wait for any messages. + assertTrue("messages are received within limit", messagesReceived.await(60, TimeUnit.SECONDS)); + assertEquals(messageCount, msgs.getMessageCount()); + } + + public void testNoDuplicateQueueSubs() throws Exception { + + bridgeAllBrokers("default", 3, true); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + String brokerName = "BrokerA"; + MessageConsumer consumer = createConsumer(brokerName, dest); + + // wait for advisories + Thread.sleep(2000); + + // verify there is one consumer on each broker, no cycles + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + verifyConsumerCount(broker, 1, dest); + } + + consumer.close(); + + // wait for advisories + Thread.sleep(2000); + + // verify there is no more consumers + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + verifyConsumerCount(broker, 0, dest); + } + } + + + public void testNoDuplicateQueueSubsHasLowestPriority() throws Exception { + boolean suppressQueueDuplicateSubscriptions = true; + boolean decreaseNetworkConsumerPriority = true; + bridgeAllBrokers("default", 3, suppressQueueDuplicateSubscriptions, decreaseNetworkConsumerPriority); + + // Setup destination + final Destination dest = createDestination("TEST.FOO", false); + + // delay the advisory messages so that one can percolate fully (cyclicly) before the other + BrokerItem brokerB = brokers.get("BrokerA"); + brokerB.broker.setPlugins(new BrokerPlugin[]{new BrokerPlugin() { + + public Broker installPlugin(Broker broker) throws Exception { + return new BrokerFilter(broker) { + + final AtomicInteger count = new AtomicInteger(); + @Override + public void preProcessDispatch( + MessageDispatch messageDispatch) { + if (messageDispatch.getDestination().getPhysicalName().contains("ActiveMQ.Advisory.Consumer")) { + // lets delay the first advisory + if (count.getAndIncrement() == 0) { + LOG.info("Sleeping on first advisory: " + messageDispatch); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + super.postProcessDispatch(messageDispatch); + } + + }; + }} + }); + + startAllBrokers(); + waitForBridgeFormation(); + + + // Setup consumers + String brokerName = "BrokerA"; + createConsumer(brokerName, dest); + + // wait for advisories + Thread.sleep(5000); + + // verify there is one consumer on each broker, no cycles + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + verifyConsumerCount(broker, 1, dest); + if (!brokerName.equals(broker.getBrokerName())) { + verifyConsumePriority(broker, ConsumerInfo.NETWORK_CONSUMER_PRIORITY, dest); + } + } + } + + + public void testDuplicateQueueSubs() throws Exception { + + configureBroker(createBroker("BrokerD")); + + bridgeAllBrokers("default", 3, false); + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + String brokerName = "BrokerA"; + MessageConsumer consumer = createConsumer(brokerName, dest); + + // wait for advisories + Thread.sleep(2000); + + verifyConsumerCount(brokers.get(brokerName).broker, 1, dest); + + // in a cyclic network, other brokers will get second order consumer + // an alternative route to A via each other + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + if (!brokerName.equals(broker.getBrokerName())) { + verifyConsumerCount(broker, 5, dest); + verifyConsumePriority(broker, ConsumerInfo.NORMAL_PRIORITY, dest); + } + } + + consumer.close(); + + // wait for advisories + Thread.sleep(2000); + + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + if (!brokerName.equals(broker.getBrokerName())) { + logConsumerCount(broker, 0, dest); + } + } + + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + verifyConsumerCount(broker, 0, dest); + } + } + + private void verifyConsumerCount(BrokerService broker, int count, final Destination dest) throws Exception { + final RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + waitFor(new Condition() { + public boolean isSatisified() throws Exception { + return !regionBroker.getDestinations(ActiveMQDestination.transform(dest)).isEmpty(); + } + }); + Queue internalQueue = (Queue) regionBroker.getDestinations(ActiveMQDestination.transform(dest)).iterator().next(); + LOG.info("Verify: consumer count on " + broker.getBrokerName() + " matches:" + count + ", val:" + internalQueue.getConsumers().size()); + assertEquals("consumer count on " + broker.getBrokerName() + " matches for q: " + internalQueue, count, internalQueue.getConsumers().size()); + } + + private void logConsumerCount(BrokerService broker, int count, final Destination dest) throws Exception { + final RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + waitFor(new Condition() { + public boolean isSatisified() throws Exception { + return !regionBroker.getDestinations(ActiveMQDestination.transform(dest)).isEmpty(); + } + }); + Queue internalQueue = (Queue) regionBroker.getDestinations(ActiveMQDestination.transform(dest)).iterator().next(); + LOG.info("Verify: consumer count on " + broker.getBrokerName() + " matches:" + count + ", val:" + internalQueue.getConsumers().size()); + } + + private void verifyConsumePriority(BrokerService broker, byte expectedPriority, Destination dest) throws Exception { + RegionBroker regionBroker = (RegionBroker) broker.getRegionBroker(); + Queue internalQueue = (Queue) regionBroker.getDestinations(ActiveMQDestination.transform(dest)).iterator().next(); + for (Subscription consumer : internalQueue.getConsumers()) { + assertEquals("consumer on " + broker.getBrokerName() + " matches priority: " + internalQueue, expectedPriority, consumer.getConsumerInfo().getPriority()); + } + } + + @Override + public void configureBroker(BrokerService brokerService) { + brokerService.setBrokerId(brokerService.getBrokerName()); + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=false&useJmx=false")); + createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB?persistent=false&useJmx=false")); + createBroker(new URI("broker:(tcp://localhost:61618)/BrokerC?persistent=false&useJmx=false")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerQueueNetworkUsingTcpTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerQueueNetworkUsingTcpTest.java new file mode 100644 index 0000000000..2a87b7d06e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerQueueNetworkUsingTcpTest.java @@ -0,0 +1,70 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.DemandForwardingBridge; +import org.apache.activemq.network.NetworkBridgeConfiguration; +import org.apache.activemq.transport.TransportFactory; + +/** + * + */ +public class ThreeBrokerQueueNetworkUsingTcpTest extends ThreeBrokerQueueNetworkTest { + protected List bridges; + + protected void bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker) throws Exception { + List remoteTransports = remoteBroker.getTransportConnectors(); + List localTransports = localBroker.getTransportConnectors(); + + URI remoteURI; + URI localURI; + if (!remoteTransports.isEmpty() && !localTransports.isEmpty()) { + remoteURI = remoteTransports.get(0).getConnectUri(); + localURI = localTransports.get(0).getConnectUri(); + + // Ensure that we are connecting using tcp + if (remoteURI.toString().startsWith("tcp:") && localURI.toString().startsWith("tcp:")) { + NetworkBridgeConfiguration config = new NetworkBridgeConfiguration(); + config.setBrokerName(localBroker.getBrokerName()); + DemandForwardingBridge bridge = new DemandForwardingBridge(config, TransportFactory.connect(localURI), TransportFactory.connect(remoteURI)); + bridge.setBrokerService(localBroker); + bridges.add(bridge); + + bridge.start(); + } else { + throw new Exception("Remote broker or local broker is not using tcp connectors"); + } + } else { + throw new Exception("Remote broker or local broker has no registered connectors."); + } + + maxSetupTime = 2000; + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + bridges = new ArrayList(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerStompTemporaryQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerStompTemporaryQueueTest.java new file mode 100644 index 0000000000..eb987440a7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerStompTemporaryQueueTest.java @@ -0,0 +1,176 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.transport.stomp.Stomp; +import org.apache.activemq.transport.stomp.StompConnection; +import org.apache.activemq.transport.stomp.StompFrame; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class ThreeBrokerStompTemporaryQueueTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ThreeBrokerStompTemporaryQueueTest.class); + private StompConnection stompConnection; + + @Override + protected NetworkConnector bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker, boolean dynamicOnly, int networkTTL, boolean conduit, boolean failover) throws Exception { + List transportConnectors = remoteBroker.getTransportConnectors(); + URI remoteURI; + if (!transportConnectors.isEmpty()) { + remoteURI = transportConnectors.get(0).getConnectUri(); + NetworkConnector connector = new DiscoveryNetworkConnector(new URI("static:" + remoteURI)); + connector.setName(localBroker.getBrokerName() + remoteBroker.getBrokerName()); + localBroker.addNetworkConnector(connector); + maxSetupTime = 2000; + return connector; + } else { + throw new Exception("Remote broker has no registered connectors."); + } + } + + public void testStompTemporaryQueue() throws Exception { + // Setup broker networks + bridgeAndConfigureBrokers("BrokerA", "BrokerB"); + bridgeAndConfigureBrokers("BrokerA", "BrokerC"); + bridgeAndConfigureBrokers("BrokerB", "BrokerA"); + bridgeAndConfigureBrokers("BrokerB", "BrokerC"); + bridgeAndConfigureBrokers("BrokerC", "BrokerA"); + bridgeAndConfigureBrokers("BrokerC", "BrokerB"); + + startAllBrokers(); + waitForBridgeFormation(); + + Thread.sleep(1000); + + stompConnection = new StompConnection(); + stompConnection.open("localhost", 61614); + // Creating a temp queue + stompConnection.sendFrame("CONNECT\n" + "login:system\n" + "passcode:manager\n\n" + Stomp.NULL); + + StompFrame frame = stompConnection.receive(); + assertTrue(frame.toString().startsWith("CONNECTED")); + + stompConnection.subscribe("/temp-queue/meaningless", "auto"); + stompConnection.send("/temp-queue/meaningless", "Hello World"); + + frame = stompConnection.receive(3000); + assertEquals("Hello World", frame.getBody()); + + Thread.sleep(1000); + + assertEquals("Destination", 1, brokers.get("BrokerA").broker.getAdminView().getTemporaryQueues().length); + assertEquals("Destination", 1, brokers.get("BrokerB").broker.getAdminView().getTemporaryQueues().length); + assertEquals("Destination", 1, brokers.get("BrokerC").broker.getAdminView().getTemporaryQueues().length); + + int advisoryTopicsForTempQueues; + advisoryTopicsForTempQueues = countTopicsByName("BrokerA", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should be present", 1, advisoryTopicsForTempQueues); + + advisoryTopicsForTempQueues = countTopicsByName("BrokerB", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should be present", 1, advisoryTopicsForTempQueues); + + advisoryTopicsForTempQueues = countTopicsByName("BrokerC", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should be present", 1, advisoryTopicsForTempQueues); + + stompConnection.disconnect(); + + Thread.sleep(1000); + + advisoryTopicsForTempQueues = countTopicsByName("BrokerA", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should have been deleted", 0, advisoryTopicsForTempQueues); + advisoryTopicsForTempQueues = countTopicsByName("BrokerB", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should have been deleted", 0, advisoryTopicsForTempQueues); + advisoryTopicsForTempQueues = countTopicsByName("BrokerC", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should have been deleted", 0, advisoryTopicsForTempQueues); + + LOG.info("Restarting brokerA"); + BrokerItem brokerItem = brokers.remove("BrokerA"); + if (brokerItem != null) { + brokerItem.destroy(); + } + + BrokerService restartedBroker = createAndConfigureBroker(new URI("broker:(tcp://localhost:61616,stomp://localhost:61613)/BrokerA")); + bridgeAndConfigureBrokers("BrokerA", "BrokerB"); + bridgeAndConfigureBrokers("BrokerA", "BrokerC"); + restartedBroker.start(); + waitForBridgeFormation(); + + Thread.sleep(3000); + + assertEquals("Destination", 0, brokers.get("BrokerA").broker.getAdminView().getTemporaryQueues().length); + assertEquals("Destination", 0, brokers.get("BrokerB").broker.getAdminView().getTemporaryQueues().length); + assertEquals("Destination", 0, brokers.get("BrokerC").broker.getAdminView().getTemporaryQueues().length); + + advisoryTopicsForTempQueues = countTopicsByName("BrokerA", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should have been deleted", 0, advisoryTopicsForTempQueues); + advisoryTopicsForTempQueues = countTopicsByName("BrokerB", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should have been deleted", 0, advisoryTopicsForTempQueues); + advisoryTopicsForTempQueues = countTopicsByName("BrokerC", "ActiveMQ.Advisory.Consumer.Queue.ID"); + assertEquals("Advisory topic should have been deleted", 0, advisoryTopicsForTempQueues); + } + + private int countTopicsByName(String broker, String name) + throws Exception { + int advisoryTopicsForTempQueues = 0; + for(int i=0; iChristian Posta + */ +public class ThreeBrokerTempDestDemandSubscriptionCleanupTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ThreeBrokerTempDestDemandSubscriptionCleanupTest.class); + + boolean enableTempDestinationBridging = true; + + private static final String BROKER_A = "BrokerA"; + private static final String BROKER_B = "BrokerB"; + private static final String BROKER_C = "BrokerC"; + + private static final String ECHO_QUEUE_NAME = "echo"; + private static final int NUM_ITER = 100; + private static final long CONSUME_TIMEOUT = 500; + + + /** + * So we network three brokers together, and send a message with request-reply semantics. + * The message goes to an echo service listening on broker C. We send a message on a queue + * to broker A which gets demand forwarded to broker C. the echo service will respond to the + * temp destination listed in the JMSReplyTo header. that will get demand forwarded back to + * broker A. When the consumer of the temp dest on broker A closes, that subscription should + * be removed on broker A. advisories firing from broker A to broker B should remove that + * subscription on broker B. advisories firing from broker B to broker C should remove that + * subscription on broker C. + * + * @throws Exception + */ + public void testSubscriptionsCleanedUpRace() throws Exception { + + final BrokerItem brokerA = brokers.get(BROKER_A); + + + Runnable tester = new Runnable() { + + @Override + public void run() { + for (int i = 0; i < NUM_ITER; i++) { + + Connection conn = null; + try { + conn = brokerA.createConnection(); + + conn.start(); + + final Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = sess.createQueue(ECHO_QUEUE_NAME); + + MessageProducer producer = sess.createProducer(destination); + + LOG.info("Starting iter: " + i); + Destination replyTo = sess.createTemporaryQueue(); + MessageConsumer responseConsumer = sess.createConsumer(replyTo); + + Message message = sess.createTextMessage("Iteration: " + i); + message.setJMSReplyTo(replyTo); + + producer.send(message); + + TextMessage response = (TextMessage)responseConsumer.receive(CONSUME_TIMEOUT); + assertNotNull("We should have gotten a response, but didn't for iter: " + i, response); + assertEquals("We got the wrong response from the echo service", "Iteration: " + i, response.getText()); + + + // so we close the consumer so that an actual RemoveInfo command gets propogated through the + // network + responseConsumer.close(); + conn.close(); + + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + + } + } + }; + + ExecutorService threadService = Executors.newFixedThreadPool(2); + threadService.submit(tester); + threadService.submit(tester); + + threadService.shutdown(); + assertTrue("executor done on time", threadService.awaitTermination(30l, TimeUnit.SECONDS)); + + // for the real test... we should not have any subscriptions left on broker C for the temp dests + BrokerItem brokerC = brokers.get(BROKER_C); + RegionBroker regionBroker = (RegionBroker) brokerC.broker.getRegionBroker(); + final AbstractRegion region = (AbstractRegion) regionBroker.getTempQueueRegion(); + + assertTrue("There were no lingering temp-queue destinations", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("Lingering temps: " + region.getSubscriptions().size()); + return 0 == region.getSubscriptions().size(); + } + })); + } + + + /** + * This test is slightly different from the above. We don't explicitly close the consumer down + * (which we did in the previous test to force the RemoveInfo to be sent). Here we just close + * the connection which should still clean up the subscriptions and temp destinations on the + * networked brokers. + * + * @throws Exception + */ + public void testSubscriptionsCleanedUpAfterConnectionClose() throws Exception { + + final BrokerItem brokerA = brokers.get(BROKER_A); + + for (int i = 0; i < NUM_ITER; i++) { + + Connection conn = null; + try { + conn = brokerA.createConnection(); + + conn.start(); + + final Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = sess.createQueue(ECHO_QUEUE_NAME); + + MessageProducer producer = sess.createProducer(destination); + + LOG.info("Starting iter: " + i); + Destination replyTo = sess.createTemporaryQueue(); + MessageConsumer responseConsumer = sess.createConsumer(replyTo); + + Message message = sess.createTextMessage("Iteration: " + i); + message.setJMSReplyTo(replyTo); + + producer.send(message); + + TextMessage response = (TextMessage)responseConsumer.receive(CONSUME_TIMEOUT); + assertNotNull("We should have gotten a response, but didn't for iter: " + i, response); + assertEquals("We got the wrong response from the echo service", "Iteration: " + i, response.getText()); + + + // so closing the connection without closing the consumer first will leak subscriptions + // in a nob? +// responseConsumer.close(); + conn.close(); + + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + + } + + // for the real test... we should not have any subscriptions left on broker C for the temp dests + BrokerItem brokerC = brokers.get(BROKER_C); + RegionBroker regionBroker = (RegionBroker) brokerC.broker.getRegionBroker(); + final AbstractRegion region = (AbstractRegion) regionBroker.getTempQueueRegion(); + + assertTrue("There were no lingering temp-queue destinations", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + LOG.info("Lingering temps: " + region.getSubscriptions().size()); + return 0 == region.getSubscriptions().size(); + } + })); + + } + + private void installEchoClientOnBrokerC() throws Exception { + BrokerItem brokerC = brokers.get(BROKER_C); + Connection conn = brokerC.createConnection(); + conn.start(); + + final Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = sess.createQueue(ECHO_QUEUE_NAME); + MessageConsumer consumer = sess.createConsumer(destination); + + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + + TextMessage textMessage = (TextMessage) message; + + try { + Destination replyTo = message.getJMSReplyTo(); + + MessageProducer producer = sess.createProducer(replyTo); + Message response = sess.createTextMessage(textMessage.getText()); + + LOG.info("Replying to this request: " + textMessage.getText()); + producer.send(response); + producer.close(); + + } catch (JMSException e) { + e.printStackTrace(); + fail("Could not respond to an echo request"); + } + } + }); + } + + + @Override + protected void setUp() throws Exception { + super.setUp(); + createBroker(new URI("broker:(tcp://localhost:61616)/" + BROKER_A + "?persistent=false&useJmx=false")); + createBroker(new URI("broker:(tcp://localhost:61617)/" + BROKER_B + "?persistent=false&useJmx=false")); + createBroker(new URI("broker:(tcp://localhost:61618)/" + BROKER_C + "?persistent=false&useJmx=false")); + + bridgeBrokers("BrokerA", "BrokerB", false, 3); + bridgeBrokers("BrokerB", "BrokerC", false, 3); + + startAllBrokers(); + + // set up a listener on broker C that will demand forward subscriptions over the network + installEchoClientOnBrokerC(); + } + + protected NetworkConnector bridgeBrokers(String localBrokerName, String remoteBrokerName, boolean dynamicOnly, int networkTTL) throws Exception { + NetworkConnector connector = super.bridgeBrokers(localBrokerName, remoteBrokerName, dynamicOnly, networkTTL, true); + connector.setBridgeTempDestinations(enableTempDestinationBridging); + connector.setDuplex(true); + return connector; + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTempQueueNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTempQueueNetworkTest.java new file mode 100644 index 0000000000..2f7b13701e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTempQueueNetworkTest.java @@ -0,0 +1,118 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Iterator; + +import javax.jms.Connection; +import javax.jms.Session; +import javax.jms.TemporaryQueue; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.network.NetworkConnector; + +/** + * + */ +public class ThreeBrokerTempQueueNetworkTest extends JmsMultipleBrokersTestSupport { + protected static final int MESSAGE_COUNT = 100; + boolean enableTempDestinationBridging = true; + + /** + * BrokerA -> BrokerB -> BrokerC + */ + public void testTempQueueCleanup() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB", false, 2); + bridgeBrokers("BrokerB", "BrokerC", false, 2); + startAllBrokers(); + BrokerItem brokerItem = brokers.get("BrokerC"); + Connection conn = brokerItem.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue tempQ = sess.createTemporaryQueue(); + Thread.sleep(5000); + for (Iterator i = brokers.values().iterator(); i.hasNext();) { + BrokerItem bi = i.next(); + assertEquals("No queues on broker " + bi.broker.getBrokerName(), 1, bi.broker.getAdminView().getTemporaryQueues().length); + } + tempQ.delete(); + Thread.sleep(2000); + for (Iterator i = brokers.values().iterator(); i.hasNext();) { + BrokerItem bi = i.next(); + assertEquals("Temp queue left behind on broker " + bi.broker.getBrokerName(), 0, bi.broker.getAdminView().getTemporaryQueues().length); + } + } + + // this actually uses 4 brokers ... + public void testTempQueueRecovery() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB", false, 3); + bridgeBrokers("BrokerB", "BrokerC", false, 3); + startAllBrokers(); + BrokerItem brokerItem = brokers.get("BrokerC"); + Connection conn = brokerItem.createConnection(); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue tempQ = sess.createTemporaryQueue(); + Thread.sleep(5000); + for (Iterator i = brokers.values().iterator(); i.hasNext();) { + BrokerItem bi = i.next(); + assertEquals("No queues on broker " + bi.broker.getBrokerName(), 1, bi.broker.getAdminView().getTemporaryQueues().length); + } + createBroker(new URI("broker:(tcp://localhost:61619)/BrokerD?persistent=false&useJmx=true")); + bridgeBrokers("BrokerD", "BrokerA", false, 3); + BrokerItem newBroker = brokers.get("BrokerD"); + newBroker.broker.start(); + Thread.sleep(1000); + assertEquals("No queues on broker D", 1, newBroker.broker.getAdminView().getTemporaryQueues().length); + tempQ.delete(); + Thread.sleep(2000); + for (Iterator i = brokers.values().iterator(); i.hasNext();) { + BrokerItem bi = i.next(); + assertEquals("Temp queue left behind on broker " + bi.broker.getBrokerName(), 0, bi.broker.getAdminView().getTemporaryQueues().length); + } + } + + public void testTempDisable() throws Exception { + enableTempDestinationBridging = false; + try { + testTempQueueCleanup(); + } catch (Throwable e) { + // Expecting an error + return; + } + fail("Test should have failed since temp queues are disabled."); + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=false&useJmx=true")); + createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB?persistent=false&useJmx=true")); + createBroker(new URI("broker:(tcp://localhost:61618)/BrokerC?persistent=false&useJmx=true")); + } + + protected NetworkConnector bridgeBrokers(String localBrokerName, String remoteBrokerName, boolean dynamicOnly, int networkTTL) throws Exception { + NetworkConnector connector = super.bridgeBrokers(localBrokerName, remoteBrokerName, dynamicOnly, networkTTL, true); + connector.setBridgeTempDestinations(enableTempDestinationBridging); + return connector; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTopicNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTopicNetworkTest.java new file mode 100644 index 0000000000..99deb28843 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTopicNetworkTest.java @@ -0,0 +1,411 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Topic; + +import junit.framework.Test; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.util.MessageIdList; + +/** + * + */ +public class ThreeBrokerTopicNetworkTest extends JmsMultipleBrokersTestSupport { + protected static final int MESSAGE_COUNT = 100; + public boolean dynamicOnly; + + /** + * BrokerA -> BrokerB -> BrokerC + */ + public void testABandBCbrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + bridgeBrokers("BrokerB", "BrokerC"); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + + //let consumers propagate around the network + Thread.sleep(2000); + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerB", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT * 2); + msgsC.waitForMessagesToArrive(MESSAGE_COUNT * 2); + + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT * 2, msgsB.getMessageCount()); + assertEquals(MESSAGE_COUNT * 2, msgsC.getMessageCount()); + + assertEquals("Correct forwards from A", MESSAGE_COUNT, + brokers.get("BrokerA").broker.getDestination(ActiveMQDestination.transform(dest)).getDestinationStatistics().getForwards().getCount()); + } + + public void initCombosForTestABandBCbrokerNetworkWithSelectors() { + addCombinationValues("dynamicOnly", new Object[] {true, false}); + } + + /** + * BrokerA -> BrokerB -> BrokerC + */ + public void testABandBCbrokerNetworkWithSelectors() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB", dynamicOnly, 2, true); + bridgeBrokers("BrokerB", "BrokerC", dynamicOnly, 2, true); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerC", dest, "dummy = 33"); + MessageConsumer clientB = createConsumer("BrokerC", dest, "dummy > 30"); + MessageConsumer clientC = createConsumer("BrokerC", dest, "dummy = 34"); + + // let consumers propogate around the network + Thread.sleep(2000); + // Send messages + // Send messages for broker A + HashMap props = new HashMap(); + props.put("dummy", 33); + sendMessages("BrokerA", dest, MESSAGE_COUNT, props); + props.put("dummy", 34); + sendMessages("BrokerA", dest, MESSAGE_COUNT * 2, props); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerC", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerC", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT * 3); + msgsC.waitForMessagesToArrive(MESSAGE_COUNT * 2) ; + + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT * 3, msgsB.getMessageCount()); + assertEquals(MESSAGE_COUNT *2, msgsC.getMessageCount()); + } + + /** + * BrokerA <- BrokerB -> BrokerC + */ + public void testBAandBCbrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerB", "BrokerA"); + bridgeBrokers("BrokerB", "BrokerC"); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + + //let consumers propagate around the network + Thread.sleep(2000); + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerB", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT * 2); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT); + msgsC.waitForMessagesToArrive(MESSAGE_COUNT * 2); + + assertEquals(MESSAGE_COUNT * 2, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT, msgsB.getMessageCount()); + assertEquals(MESSAGE_COUNT * 2, msgsC.getMessageCount()); + } + + /** + * BrokerA -> BrokerB <- BrokerC + */ + public void testABandCBbrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + bridgeBrokers("BrokerC", "BrokerB"); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + + //let consumers propagate around the network + Thread.sleep(2000); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerB", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT * 3); + msgsC.waitForMessagesToArrive(MESSAGE_COUNT); + + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT * 3, msgsB.getMessageCount()); + assertEquals(MESSAGE_COUNT, msgsC.getMessageCount()); + } + + /** + * BrokerA <-> BrokerB <-> BrokerC + */ + public void testAllConnectedBrokerNetwork() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + bridgeBrokers("BrokerB", "BrokerA"); + bridgeBrokers("BrokerB", "BrokerC"); + bridgeBrokers("BrokerC", "BrokerB"); + bridgeBrokers("BrokerA", "BrokerC"); + bridgeBrokers("BrokerC", "BrokerA"); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + //let consumers propogate around the network + Thread.sleep(2000); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerB", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT * 3); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT * 3); + msgsC.waitForMessagesToArrive(MESSAGE_COUNT * 3); + + assertEquals(MESSAGE_COUNT * 3, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT * 3, msgsB.getMessageCount()); + assertEquals(MESSAGE_COUNT * 3, msgsC.getMessageCount()); + } + + public void testAllConnectedBrokerNetworkSingleProducerTTL() throws Exception { + + // duplicates are expected with ttl of 2 as each broker is connected to the next + // but the dups are suppressed by the store and now also by the topic sub when enableAudit + // default (true) is present in a matching destination policy entry + int networkTTL = 2; + boolean conduitSubs = true; + // Setup ring broker networks + bridgeBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerB", "BrokerA", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerB", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerC", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerA", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerC", "BrokerA", dynamicOnly, networkTTL, conduitSubs); + + PolicyMap policyMap = new PolicyMap(); + // enable audit is on by default just need to give it matching policy entry + // so it will be applied to the topic subscription + policyMap.setDefaultEntry(new PolicyEntry()); + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + broker.setDestinationPolicy(policyMap); + broker.setDeleteAllMessagesOnStartup(true); + } + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + //let consumers propogate around the network + Thread.sleep(2000); + + // Send messages + sendMessages("BrokerA", dest, 1); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(1); + msgsB.waitForMessagesToArrive(1); + msgsC.waitForMessagesToArrive(1); + + // ensure we don't get any more messages + Thread.sleep(2000); + + assertEquals(1, msgsA.getMessageCount()); + assertEquals(1, msgsB.getMessageCount()); + assertEquals(1, msgsC.getMessageCount()); + } + + public void testAllConnectedBrokerNetworkDurableSubTTL() throws Exception { + int networkTTL = 2; + boolean conduitSubs = true; + // Setup ring broker network + bridgeBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerB", "BrokerA", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerB", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerC", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerA", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + bridgeBrokers("BrokerC", "BrokerA", dynamicOnly, networkTTL, conduitSubs); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createDurableSubscriber("BrokerA", (Topic)dest, "clientA"); + MessageConsumer clientB = createDurableSubscriber("BrokerB", (Topic)dest, "clientB"); + MessageConsumer clientC = createDurableSubscriber("BrokerC", (Topic)dest, "clientC"); + //let consumers propogate around the network + Thread.sleep(2000); + + // Send messages + sendMessages("BrokerA", dest, 1); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(1); + msgsB.waitForMessagesToArrive(1); + msgsC.waitForMessagesToArrive(1); + + // ensure we don't get any more messages + Thread.sleep(2000); + + assertEquals(1, msgsA.getMessageCount()); + assertEquals(1, msgsB.getMessageCount()); + assertEquals(1, msgsC.getMessageCount()); + } + + /** + * BrokerA <-> BrokerB <-> BrokerC + */ + public void testAllConnectedUsingMulticast() throws Exception { + // Setup broker networks + bridgeAllBrokers(); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + MessageConsumer clientC = createConsumer("BrokerC", dest); + + //let consumers propogate around the network + Thread.sleep(2000); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + sendMessages("BrokerB", dest, MESSAGE_COUNT); + sendMessages("BrokerC", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT * 3); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT * 3); + msgsC.waitForMessagesToArrive(MESSAGE_COUNT * 3); + + assertEquals(MESSAGE_COUNT * 3, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT * 3, msgsB.getMessageCount()); + assertEquals(MESSAGE_COUNT * 3, msgsC.getMessageCount()); + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + String options = new String("?persistent=false&useJmx=false"); + createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA" + options)); + createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB" + options)); + createBroker(new URI("broker:(tcp://localhost:61618)/BrokerC" + options)); + } + + @Override + protected void configureBroker(BrokerService broker) { + broker.setBrokerId(broker.getBrokerName()); + } + + public static Test suite() { + return suite(ThreeBrokerTopicNetworkTest.class); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTopicNetworkUsingTcpTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTopicNetworkUsingTcpTest.java new file mode 100644 index 0000000000..6e50b6ecb0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerTopicNetworkUsingTcpTest.java @@ -0,0 +1,70 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.DemandForwardingBridge; +import org.apache.activemq.network.NetworkBridgeConfiguration; +import org.apache.activemq.transport.TransportFactory; + +/** + * + */ +public class ThreeBrokerTopicNetworkUsingTcpTest extends ThreeBrokerTopicNetworkTest { + protected List bridges; + + protected void bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker) throws Exception { + List remoteTransports = remoteBroker.getTransportConnectors(); + List localTransports = localBroker.getTransportConnectors(); + + URI remoteURI; + URI localURI; + if (!remoteTransports.isEmpty() && !localTransports.isEmpty()) { + remoteURI = remoteTransports.get(0).getConnectUri(); + localURI = localTransports.get(0).getConnectUri(); + + // Ensure that we are connecting using tcp + if (remoteURI.toString().startsWith("tcp:") && localURI.toString().startsWith("tcp:")) { + NetworkBridgeConfiguration config = new NetworkBridgeConfiguration(); + config.setBrokerName(localBroker.getBrokerName()); + DemandForwardingBridge bridge = new DemandForwardingBridge(config, TransportFactory.connect(localURI), TransportFactory.connect(remoteURI)); + bridge.setBrokerService(localBroker); + bridges.add(bridge); + + bridge.start(); + } else { + throw new Exception("Remote broker or local broker is not using tcp connectors"); + } + } else { + throw new Exception("Remote broker or local broker has no registered connectors."); + } + + maxSetupTime = 2000; + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + bridges = new ArrayList(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerVirtualTopicNetworkLevelDBTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerVirtualTopicNetworkLevelDBTest.java new file mode 100644 index 0000000000..a9f5955b28 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerVirtualTopicNetworkLevelDBTest.java @@ -0,0 +1,34 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.IOException; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.leveldb.LevelDBStore; + + +public class ThreeBrokerVirtualTopicNetworkLevelDBTest extends ThreeBrokerVirtualTopicNetworkTest { + + protected void configurePersistenceAdapter(BrokerService broker) throws IOException { + File dataFileDir = new File("target/test-data/leveldb/" + broker.getBrokerName()); + LevelDBStore adapter = new LevelDBStore(); + adapter.setDirectory(dataFileDir); + broker.setPersistenceAdapter(adapter); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerVirtualTopicNetworkTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerVirtualTopicNetworkTest.java new file mode 100644 index 0000000000..a8e8f5046d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/ThreeBrokerVirtualTopicNetworkTest.java @@ -0,0 +1,186 @@ +/** + * 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.usecases; + +import java.io.File; +import java.io.IOException; +import java.net.URI; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class ThreeBrokerVirtualTopicNetworkTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(ThreeBrokerVirtualTopicNetworkTest.class); + protected static final int MESSAGE_COUNT = 1; + public boolean dynamicOnly = false; + + + public void testNetworkVirtualTopic() throws Exception { + int networkTTL = 6; + boolean conduitSubs = true; + // Setup broker networks + bridgeAndConfigureBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + bridgeAndConfigureBrokers("BrokerA", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + bridgeAndConfigureBrokers("BrokerB", "BrokerA", dynamicOnly, networkTTL, conduitSubs); + bridgeAndConfigureBrokers("BrokerB", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + bridgeAndConfigureBrokers("BrokerC", "BrokerA", dynamicOnly, networkTTL, conduitSubs); + bridgeAndConfigureBrokers("BrokerC", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", createDestination("Consumer.A.TEST.FOO", false)); + MessageConsumer clientB = createConsumer("BrokerB", createDestination("Consumer.B.TEST.FOO", false)); + MessageConsumer clientC = createConsumer("BrokerC", createDestination("Consumer.C.TEST.FOO", false)); + + Thread.sleep(2000); + + // Send messages + sendMessages("BrokerA", dest, 1); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + MessageIdList msgsC = getConsumerMessages("BrokerC", clientC); + + msgsA.waitForMessagesToArrive(1); + msgsB.waitForMessagesToArrive(1); + msgsC.waitForMessagesToArrive(1); + + // ensure we don't get any more messages + Thread.sleep(2000); + + assertEquals(1, msgsA.getMessageCount()); + assertEquals(1, msgsB.getMessageCount()); + assertEquals(1, msgsC.getMessageCount()); + + // restart to ensure no hanging messages + LOG.info("Restarting brokerA"); + BrokerItem brokerItem = brokers.remove("BrokerA"); + if (brokerItem != null) { + brokerItem.destroy(); + } + + BrokerService restartedBroker = createAndConfigureBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?useJmx=false")); + bridgeAndConfigureBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + bridgeAndConfigureBrokers("BrokerA", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + restartedBroker.start(); + waitForBridgeFormation(); + + clientA = createConsumer("BrokerA", createDestination("Consumer.A.TEST.FOO", false)); + LOG.info("recreated clientA"); + + Thread.sleep(2000); + + sendMessages("BrokerA", dest, 10); + + msgsA = getConsumerMessages("BrokerA", clientA); + + msgsA.waitForMessagesToArrive(10); + msgsB.waitForMessagesToArrive(11); + msgsC.waitForMessagesToArrive(11); + + // ensure we don't get any more messages + Thread.sleep(2000); + + LOG.info("MessagesA: " + msgsA.getMessageIds()); + assertEquals(10, msgsA.getMessageCount()); + assertEquals(11, msgsB.getMessageCount()); + assertEquals(11, msgsC.getMessageCount()); + + // restart to ensure no hanging messages + LOG.info("Restarting brokerA again"); + brokerItem = brokers.remove("BrokerA"); + if (brokerItem != null) { + brokerItem.destroy(); + } + + restartedBroker = createAndConfigureBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?useJmx=false")); + bridgeAndConfigureBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduitSubs); + bridgeAndConfigureBrokers("BrokerA", "BrokerC", dynamicOnly, networkTTL, conduitSubs); + restartedBroker.start(); + waitForBridgeFormation(); + + clientA = createConsumer("BrokerA", createDestination("Consumer.A.TEST.FOO", false)); + LOG.info("recreated clientA again"); + + Thread.sleep(2000); + + msgsA = getConsumerMessages("BrokerA", clientA); + + // ensure we don't get any more messages + Thread.sleep(5000); + + LOG.info("Extra MessagesA: " + msgsA.getMessageIds()); + assertEquals(0, msgsA.getMessageCount()); + assertEquals(11, msgsB.getMessageCount()); + assertEquals(11, msgsC.getMessageCount()); + } + + + private void bridgeAndConfigureBrokers(String local, String remote, boolean dynamicOnly, int networkTTL, boolean conduitSubs) throws Exception { + NetworkConnector bridge = bridgeBrokers(local, remote, dynamicOnly, networkTTL, conduitSubs); + bridge.setDecreaseNetworkConsumerPriority(true); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + String options = new String("?useJmx=false&deleteAllMessagesOnStartup=true"); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61616)/BrokerA" + options)); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61617)/BrokerB" + options)); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61618)/BrokerC" + options)); + } + + private BrokerService createAndConfigureBroker(URI uri) throws Exception { + BrokerService broker = createBroker(uri); + + configurePersistenceAdapter(broker); + + // make all topics virtual and consumers use the default prefix + VirtualDestinationInterceptor virtualDestinationInterceptor = new VirtualDestinationInterceptor(); + virtualDestinationInterceptor.setVirtualDestinations(new VirtualDestination[]{new VirtualTopic()}); + DestinationInterceptor[] destinationInterceptors = new DestinationInterceptor[]{virtualDestinationInterceptor}; + broker.setDestinationInterceptors(destinationInterceptors); + return broker; + } + + protected void configurePersistenceAdapter(BrokerService broker) throws IOException { + File dataFileDir = new File("target/test-amq-data/kahadb/" + broker.getBrokerName()); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(dataFileDir); + broker.setPersistenceAdapter(kaha); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicDurableConnectStatsTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicDurableConnectStatsTest.java new file mode 100644 index 0000000000..3612fdded1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicDurableConnectStatsTest.java @@ -0,0 +1,273 @@ +/** + * 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.usecases; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.Date; +import java.util.Vector; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import junit.framework.Test; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.DurableSubscriptionViewMBean; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TopicDurableConnectStatsTest extends org.apache.activemq.TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(TopicDurableConnectStatsTest.class); + private BrokerService broker; + private ActiveMQTopic topic; + private final Vector exceptions = new Vector(); + private final int messageSize = 4000; + protected MBeanServerConnection mbeanServer; + protected String domain = "org.apache.activemq"; + private ActiveMQConnectionFactory connectionFactory = null; + final int numMessages = 20; + + private static Session session2 = null; + + @Override + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + + connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); + + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setAll(10); + connectionFactory.setPrefetchPolicy(prefetchPolicy); + + connectionFactory.setWatchTopicAdvisories(false); + return connectionFactory; + } + + @Override + protected Connection createConnection() throws Exception { + return createConnection("cliName"); + } + + protected Connection createConnection(String name) throws Exception { + Connection con = super.createConnection(); + con.setClientID(name); + con.start(); + return con; + } + + public static Test suite() { + return suite(TopicDurableConnectStatsTest.class); + } + + @Override + protected void setUp() throws Exception { + exceptions.clear(); + topic = (ActiveMQTopic) createDestination(); + + createBroker(); + mbeanServer = ManagementFactory.getPlatformMBeanServer(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + destroyBroker(); + } + + private void createBroker() throws Exception { + createBroker(true); + } + + private void createBroker(boolean deleteAllMessages) throws Exception { + broker = BrokerFactory.createBroker("broker:(vm://" + getName(true) + ")"); + broker.setBrokerName(getName(true)); + broker.setDeleteAllMessagesOnStartup(deleteAllMessages); + broker.setAdvisorySupport(false); + broker.addConnector("tcp://0.0.0.0:0"); + + setDefaultPersistenceAdapter(broker); + broker.start(); + } + + private void destroyBroker() throws Exception { + if (broker != null) + broker.stop(); + } + + protected ObjectName assertRegisteredObjectName(String name) throws MalformedObjectNameException, NullPointerException { + ObjectName objectName = new ObjectName(name); + + LOG.info("** Looking for " + name); + try { + if (mbeanServer.isRegistered(objectName)) { + LOG.info("Bean Registered: " + objectName); + } else { + LOG.info("Couldn't find Mbean! " + objectName); + + } + } catch (IOException e) { + e.printStackTrace(); + } + return objectName; + } + + public void testPendingTopicStat() throws Exception { + + Connection consumerCon = createConnection("cliId1"); + Session consumerSession = consumerCon.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer1 = consumerSession.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + assertNotNull(consumer1); + + DurableSubscriptionViewMBean subscriber1 = null; + + ObjectName query = new ObjectName(domain + ":type=Broker,brokerName=" + getName(true) + ",destinationType=Topic,destinationName=" + topic.getTopicName() + ",endpoint=Consumer,clientId=cliId1,consumerId=*"); + + java.util.Setset = mbeanServer.queryNames(query,null); + + ObjectName subscriberObjName1 = set.iterator().next(); + subscriber1 = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, subscriberObjName1, DurableSubscriptionViewMBean.class, true); + + LOG.info("Beginning Pending Queue Size count: " + subscriber1.getPendingQueueSize()); + LOG.info("Prefetch Limit: " + subscriber1.getPrefetchSize()); + + assertEquals("no pending", 0, subscriber1.getPendingQueueSize()); + assertEquals("Prefetch Limit ", 10, subscriber1.getPrefetchSize()); + + + Connection producerCon = createConnection("x"); + Session producerSessions = producerCon.createSession(true, Session.AUTO_ACKNOWLEDGE); + + + MessageProducer producer = producerSessions.createProducer(topic); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + + int i = 0; + for (; i < numMessages; i++) { + + if (i == 15) { + // kill consumer + + LOG.info("Killing consumer at 15"); + consumerSession.close(); + consumerCon.close(); + } + + TextMessage message = producerSessions.createTextMessage(createMessageText(i)); + message.setJMSExpiration(0); + message.setStringProperty("filter", "true"); + producer.send(topic, message); + producerSessions.commit(); + + } + LOG.info("Sent " + i + " messages in total"); + producerCon.close(); + + LOG.info("Pending Queue Size count: " + subscriber1.getPendingQueueSize()); + assertEquals("pending as expected", 20, subscriber1.getPendingQueueSize()); + + LOG.info("Re-connect client and consume messages"); + Connection con2 = createConnection("cliId1"); + session2 = con2.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer2 = session2.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + + + final Listener listener = new Listener(); + consumer2.setMessageListener(listener); + + assertTrue("received all sent", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return numMessages == listener.count; + } + })); + + LOG.info("Received: " + listener.count); + + int pq = subscriber1.getPendingQueueSize(); + LOG.info("Pending Queue Size count: " + pq); + assertEquals("Pending queue after consumed", 0, pq); + + session2.close(); + con2.close(); + LOG.info("FINAL Pending Queue Size count (after consumer close): " + subscriber1.getPendingQueueSize()); + } + + + private String createMessageText(int index) { + StringBuffer buffer = new StringBuffer(messageSize); + buffer.append("Message: " + index + " sent at: " + new Date()); + if (buffer.length() > messageSize) { + return buffer.substring(0, messageSize); + } + for (int i = buffer.length(); i < messageSize; i++) { + buffer.append(' '); + } + return buffer.toString(); + } + + + public static class Listener implements MessageListener { + int count = 0; + String id = null; + + Listener() { + } + + @Override + public void onMessage(Message message) { + count++; + try { + session2.commit(); + } catch (JMSException e1) { + e1.printStackTrace(); + } + + if (id != null) { + try { + LOG.info(id + ", " + message.getJMSMessageID()); + } catch (Exception ignored) { + } + } + + try { + Thread.sleep(2); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicProducerFlowControlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicProducerFlowControlTest.java new file mode 100644 index 0000000000..9ea1446e41 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicProducerFlowControlTest.java @@ -0,0 +1,189 @@ +/** + * 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.usecases; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TopicProducerFlowControlTest extends TestCase implements MessageListener { + private static final Logger LOG = LoggerFactory.getLogger(TopicProducerFlowControlTest.class); + private static final String brokerName = "testBroker"; + private static final String brokerUrl = "vm://" + brokerName; + protected static final int destinationMemLimit = 2097152; // 2MB + private static final AtomicLong produced = new AtomicLong(); + private static final AtomicLong consumed = new AtomicLong(); + private static final int numMessagesToSend = 50000; + + private BrokerService broker; + + protected void setUp() throws Exception { + // Setup and start the broker + broker = new BrokerService(); + broker.setBrokerName(brokerName); + broker.setPersistent(false); + broker.setSchedulerSupport(false); + broker.setUseJmx(false); + broker.setUseShutdownHook(false); + broker.addConnector(brokerUrl); + + // Setup the destination policy + PolicyMap pm = new PolicyMap(); + + // Setup the topic destination policy + PolicyEntry tpe = new PolicyEntry(); + tpe.setTopic(">"); + tpe.setMemoryLimit(destinationMemLimit); + tpe.setProducerFlowControl(true); + tpe.setAdvisoryWhenFull(true); + + // Setup the topic destination policy + PolicyEntry qpe = new PolicyEntry(); + qpe.setQueue(">"); + qpe.setMemoryLimit(destinationMemLimit); + qpe.setProducerFlowControl(true); + qpe.setQueuePrefetch(1); + qpe.setAdvisoryWhenFull(true); + + pm.setPolicyEntries(Arrays.asList(new PolicyEntry[]{tpe, qpe})); + + setDestinationPolicy(broker, pm); + + // Start the broker + broker.start(); + broker.waitUntilStarted(); + } + + protected void setDestinationPolicy(BrokerService broker, PolicyMap pm) { + broker.setDestinationPolicy(pm); + } + + protected void tearDown() throws Exception { + broker.stop(); + broker.waitUntilStopped(); + } + + public void testTopicProducerFlowControl() throws Exception { + + // Create the connection factory + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrl); + connectionFactory.setAlwaysSyncSend(true); + connectionFactory.setProducerWindowSize(1024); + + ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy(); + prefetchPolicy.setAll(5000); + connectionFactory.setPrefetchPolicy(prefetchPolicy); + // Start the test destination listener + Connection c = connectionFactory.createConnection(); + c.start(); + Session listenerSession = c.createSession(false, 1); + Destination destination = createDestination(listenerSession); + + listenerSession.createConsumer(destination).setMessageListener(new TopicProducerFlowControlTest()); + final AtomicInteger blockedCounter = new AtomicInteger(0); + listenerSession.createConsumer(new ActiveMQTopic(AdvisorySupport.FULL_TOPIC_PREFIX + ">")).setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + LOG.info("Got full advisory, blockedCounter: " + blockedCounter.get()); + blockedCounter.incrementAndGet(); + } + }); + + // Start producing the test messages + final Session session = connectionFactory.createConnection().createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(destination); + + Thread producingThread = new Thread("Producing Thread") { + public void run() { + try { + for (long i = 0; i < numMessagesToSend; i++) { + producer.send(session.createTextMessage("test")); + + long count = produced.incrementAndGet(); + if (count % 10000 == 0) { + LOG.info("Produced " + count + " messages"); + } + } + } catch (Throwable ex) { + ex.printStackTrace(); + } finally { + try { + producer.close(); + session.close(); + } catch (Exception e) { + } + } + } + }; + + producingThread.start(); + + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return consumed.get() == numMessagesToSend; + } + }, 5 * 60 * 1000); // give it plenty of time before failing + + assertEquals("Didn't produce all messages", numMessagesToSend, produced.get()); + assertEquals("Didn't consume all messages", numMessagesToSend, consumed.get()); + + assertTrue("Producer got blocked", Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return blockedCounter.get() > 0; + } + }, 5 * 1000)); + } + + protected Destination createDestination(Session listenerSession) throws Exception { + return new ActiveMQTopic("test"); + } + + @Override + public void onMessage(Message message) { + long count = consumed.incrementAndGet(); + if (count % 100 == 0) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + if (count % 10000 == 0) { + LOG.info("\tConsumed " + count + " messages"); + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicRedeliverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicRedeliverTest.java new file mode 100644 index 0000000000..38134916fe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicRedeliverTest.java @@ -0,0 +1,278 @@ +/** + * 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.usecases; + +import java.util.concurrent.atomic.AtomicBoolean; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +import org.apache.activemq.test.TestSupport; +import org.apache.activemq.util.IdGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TopicRedeliverTest extends TestSupport { + + private static final Logger LOG = LoggerFactory.getLogger(TopicRedeliverTest.class); + private static final int RECEIVE_TIMEOUT = 10000; + + protected int deliveryMode = DeliveryMode.PERSISTENT; + private IdGenerator idGen = new IdGenerator(); + + public TopicRedeliverTest() { + } + + public TopicRedeliverTest(String n) { + super(n); + } + + protected void setUp() throws Exception { + super.setUp(); + topic = true; + } + + /** + * test messages are acknowledged and recovered properly + * + * @throws Exception + */ + public void testClientAcknowledge() throws Exception { + Destination destination = createDestination(getClass().getName()); + Connection connection = createConnection(); + connection.setClientID(idGen.generateId()); + connection.start(); + Session consumerSession = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(destination); + Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + // send some messages + + TextMessage sent1 = producerSession.createTextMessage(); + sent1.setText("msg1"); + producer.send(sent1); + + TextMessage sent2 = producerSession.createTextMessage(); + sent1.setText("msg2"); + producer.send(sent2); + + TextMessage sent3 = producerSession.createTextMessage(); + sent1.setText("msg3"); + producer.send(sent3); + + consumer.receive(RECEIVE_TIMEOUT); + Message rec2 = consumer.receive(RECEIVE_TIMEOUT); + consumer.receive(RECEIVE_TIMEOUT); + + // ack rec2 + rec2.acknowledge(); + + TextMessage sent4 = producerSession.createTextMessage(); + sent4.setText("msg4"); + producer.send(sent4); + + Message rec4 = consumer.receive(RECEIVE_TIMEOUT); + assertTrue(rec4.equals(sent4)); + consumerSession.recover(); + rec4 = consumer.receive(RECEIVE_TIMEOUT); + assertTrue(rec4.equals(sent4)); + assertTrue(rec4.getJMSRedelivered()); + rec4.acknowledge(); + connection.close(); + + } + + /** + * Test redelivered flag is set on rollbacked transactions + * + * @throws Exception + */ + public void testRedilveredFlagSetOnRollback() throws Exception { + Destination destination = createDestination(getClass().getName()); + Connection connection = createConnection(); + connection.setClientID(idGen.generateId()); + connection.start(); + Session consumerSession = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = null; + if (topic) { + consumer = consumerSession.createDurableSubscriber((Topic)destination, "TESTRED"); + } else { + consumer = consumerSession.createConsumer(destination); + } + Session producerSession = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + TextMessage sentMsg = producerSession.createTextMessage(); + sentMsg.setText("msg1"); + producer.send(sentMsg); + producerSession.commit(); + + Message recMsg = consumer.receive(RECEIVE_TIMEOUT); + assertFalse(recMsg.getJMSRedelivered()); + recMsg = consumer.receive(RECEIVE_TIMEOUT); + consumerSession.rollback(); + recMsg = consumer.receive(RECEIVE_TIMEOUT); + assertTrue(recMsg.getJMSRedelivered()); + consumerSession.commit(); + assertTrue(recMsg.equals(sentMsg)); + assertTrue(recMsg.getJMSRedelivered()); + connection.close(); + } + + public void testNoExceptionOnRedeliveryAckWithSimpleTopicConsumer() throws Exception { + Destination destination = createDestination(getClass().getName()); + Connection connection = createConnection(); + final AtomicBoolean gotException = new AtomicBoolean(); + connection.setExceptionListener(new ExceptionListener() { + public void onException(JMSException exception) { + LOG.error("unexpected ex:" + exception); + gotException.set(true); + } + }); + connection.setClientID(idGen.generateId()); + connection.start(); + Session consumerSession = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = null; + if (topic) { + consumer = consumerSession.createConsumer((Topic)destination); + } else { + consumer = consumerSession.createConsumer(destination); + } + Session producerSession = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + TextMessage sentMsg = producerSession.createTextMessage(); + sentMsg.setText("msg1"); + producer.send(sentMsg); + producerSession.commit(); + + Message recMsg = consumer.receive(RECEIVE_TIMEOUT); + assertFalse(recMsg.getJMSRedelivered()); + recMsg = consumer.receive(RECEIVE_TIMEOUT); + consumerSession.rollback(); + recMsg = consumer.receive(RECEIVE_TIMEOUT); + assertTrue(recMsg.getJMSRedelivered()); + consumerSession.rollback(); + recMsg = consumer.receive(RECEIVE_TIMEOUT); + assertTrue(recMsg.getJMSRedelivered()); + consumerSession.commit(); + assertTrue(recMsg.equals(sentMsg)); + assertTrue(recMsg.getJMSRedelivered()); + connection.close(); + + assertFalse("no exception", gotException.get()); + } + + /** + * Check a session is rollbacked on a Session close(); + * + * @throws Exception + */ + + public void xtestTransactionRollbackOnSessionClose() throws Exception { + Destination destination = createDestination(getClass().getName()); + Connection connection = createConnection(); + connection.setClientID(idGen.generateId()); + connection.start(); + Session consumerSession = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = null; + if (topic) { + consumer = consumerSession.createDurableSubscriber((Topic)destination, "TESTRED"); + } else { + consumer = consumerSession.createConsumer(destination); + } + Session producerSession = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + TextMessage sentMsg = producerSession.createTextMessage(); + sentMsg.setText("msg1"); + producer.send(sentMsg); + + producerSession.commit(); + + Message recMsg = consumer.receive(RECEIVE_TIMEOUT); + assertFalse(recMsg.getJMSRedelivered()); + consumerSession.close(); + consumerSession = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + consumer = consumerSession.createConsumer(destination); + + recMsg = consumer.receive(RECEIVE_TIMEOUT); + consumerSession.commit(); + assertTrue(recMsg.equals(sentMsg)); + connection.close(); + } + + /** + * check messages are actuallly sent on a tx rollback + * + * @throws Exception + */ + + public void testTransactionRollbackOnSend() throws Exception { + Destination destination = createDestination(getClass().getName()); + Connection connection = createConnection(); + connection.setClientID(idGen.generateId()); + connection.start(); + Session consumerSession = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = consumerSession.createConsumer(destination); + Session producerSession = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(destination); + producer.setDeliveryMode(deliveryMode); + + TextMessage sentMsg = producerSession.createTextMessage(); + sentMsg.setText("msg1"); + producer.send(sentMsg); + producerSession.commit(); + + Message recMsg = consumer.receive(RECEIVE_TIMEOUT); + consumerSession.commit(); + assertTrue(recMsg.equals(sentMsg)); + + sentMsg = producerSession.createTextMessage(); + sentMsg.setText("msg2"); + producer.send(sentMsg); + producerSession.rollback(); + + sentMsg = producerSession.createTextMessage(); + sentMsg.setText("msg3"); + producer.send(sentMsg); + producerSession.commit(); + + recMsg = consumer.receive(RECEIVE_TIMEOUT); + assertTrue(recMsg.equals(sentMsg)); + consumerSession.commit(); + + connection.close(); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicReplicationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicReplicationTest.java new file mode 100644 index 0000000000..354f8af7fc --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicReplicationTest.java @@ -0,0 +1,116 @@ +/** + * 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.usecases; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.util.MessageIdList; +import org.springframework.core.io.ClassPathResource; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; + +public class TopicReplicationTest extends JmsMultipleBrokersTestSupport { + + public static final int MSG_COUNT = 10; + + public void testReplication() throws Exception { + createBroker(new ClassPathResource("org/apache/activemq/usecases/replication-broker1.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/replication-broker2.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/replication-broker3.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/replication-broker4.xml")); + + brokers.get("replication-broker1").broker.waitUntilStarted(); + brokers.get("replication-broker2").broker.waitUntilStarted(); + brokers.get("replication-broker3").broker.waitUntilStarted(); + brokers.get("replication-broker4").broker.waitUntilStarted(); + + Destination dest = createDestination("replication", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("replication-broker2", dest); + MessageConsumer clientB = createConsumer("replication-broker3", dest); + MessageConsumer clientC = createConsumer("replication-broker4", dest); + MessageConsumer clientD = createConsumer("replication-broker4", dest); + + //let consumers propogate around the network + Thread.sleep(2000); + + // Get message count + MessageIdList msgsA = getConsumerMessages("replication-broker2", clientA); + MessageIdList msgsB = getConsumerMessages("replication-broker3", clientB); + MessageIdList msgsC = getConsumerMessages("replication-broker4", clientC); + MessageIdList msgsD = getConsumerMessages("replication-broker4", clientD); + + + + // send messages to broker1 + sendMessages("replication-broker1", dest, MSG_COUNT); + + + msgsA.waitForMessagesToArrive(MSG_COUNT); + msgsB.waitForMessagesToArrive(MSG_COUNT); + msgsC.waitForMessagesToArrive(MSG_COUNT); + msgsD.waitForMessagesToArrive(MSG_COUNT); + + assertEquals(MSG_COUNT, msgsA.getMessageCount()); + assertEquals(MSG_COUNT, msgsB.getMessageCount()); + assertEquals(MSG_COUNT, msgsC.getMessageCount()); + assertEquals(MSG_COUNT, msgsD.getMessageCount()); + + // send messages to broker4 + sendMessages("replication-broker4", dest, MSG_COUNT); + + msgsA.waitForMessagesToArrive(2 * MSG_COUNT); + msgsB.waitForMessagesToArrive(2 * MSG_COUNT); + msgsC.waitForMessagesToArrive(2 * MSG_COUNT); + msgsD.waitForMessagesToArrive(2 * MSG_COUNT); + + assertEquals(2 * MSG_COUNT, msgsA.getMessageCount()); + assertEquals(2 * MSG_COUNT, msgsB.getMessageCount()); + assertEquals(2 * MSG_COUNT, msgsC.getMessageCount()); + assertEquals(2 * MSG_COUNT, msgsD.getMessageCount()); + + // send messages to broker3 + sendMessages("replication-broker3", dest, MSG_COUNT); + + msgsA.waitForMessagesToArrive(3 * MSG_COUNT); + msgsB.waitForMessagesToArrive(3 * MSG_COUNT); + msgsC.waitForMessagesToArrive(3 * MSG_COUNT); + msgsD.waitForMessagesToArrive(3 * MSG_COUNT); + + assertEquals(3 * MSG_COUNT, msgsA.getMessageCount()); + assertEquals(3 * MSG_COUNT, msgsB.getMessageCount()); + assertEquals(3 * MSG_COUNT, msgsC.getMessageCount()); + assertEquals(3 * MSG_COUNT, msgsD.getMessageCount()); + + // send messages to broker2 + sendMessages("replication-broker2", dest, MSG_COUNT); + + msgsA.waitForMessagesToArrive(4 * MSG_COUNT); + msgsB.waitForMessagesToArrive(4 * MSG_COUNT); + msgsC.waitForMessagesToArrive(4 * MSG_COUNT); + msgsD.waitForMessagesToArrive(4 * MSG_COUNT); + + assertEquals(4 * MSG_COUNT, msgsA.getMessageCount()); + assertEquals(4 * MSG_COUNT, msgsB.getMessageCount()); + assertEquals(4 * MSG_COUNT, msgsC.getMessageCount()); + assertEquals(4 * MSG_COUNT, msgsD.getMessageCount()); + + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicSubscriptionSlowConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicSubscriptionSlowConsumerTest.java new file mode 100644 index 0000000000..4d56601d65 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicSubscriptionSlowConsumerTest.java @@ -0,0 +1,128 @@ +/** + * 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.usecases; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.advisory.AdvisorySupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.Assert; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + + +/** + * Checks to see if "slow consumer advisory messages" are generated when + * small number of messages (2) are published to a topic which has a subscriber + * with a prefetch of one set. + * + */ + +public class TopicSubscriptionSlowConsumerTest extends TestCase { + + private static final String TOPIC_NAME = "slow.consumer"; + Connection connection; + private Session session; + private ActiveMQTopic destination; + private MessageProducer producer; + private MessageConsumer consumer; + private BrokerService brokerService; + + + public void setUp() throws Exception { + + brokerService = createBroker(); + + ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + + activeMQConnectionFactory.setWatchTopicAdvisories(true); + connection = activeMQConnectionFactory.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = new ActiveMQTopic(TOPIC_NAME); + producer = session.createProducer(destination); + + connection.start(); + } + + + + public void testPrefetchValueOne() throws Exception{ + + ActiveMQTopic consumerDestination = new ActiveMQTopic(TOPIC_NAME+"?consumer.prefetchSize=1"); + consumer = session.createConsumer(consumerDestination); + + //add a consumer to the slow consumer advisory topic. + ActiveMQTopic slowConsumerAdvisoryTopic = AdvisorySupport.getSlowConsumerAdvisoryTopic(destination); + MessageConsumer slowConsumerAdvisory = session.createConsumer(slowConsumerAdvisoryTopic); + + //publish 2 messages + Message txtMessage = session.createTextMessage("Sample Text Message"); + for(int i= 0; i<2; i++){ + producer.send(txtMessage); + } + + //consume 2 messages + for(int i= 0; i<2; i++){ + Message receivedMsg = consumer.receive(100); + Assert.assertNotNull("received msg "+i+" should not be null",receivedMsg); + } + + //check for "slow consumer" advisory message + Message slowAdvisoryMessage = slowConsumerAdvisory.receive(100); + Assert.assertNull( "should not have received a slow consumer advisory message",slowAdvisoryMessage); + + } + + + + public void tearDown() throws Exception { + consumer.close(); + producer.close(); + session.close(); + connection.close(); + brokerService.stop(); + } + + + //helper method to create a broker with slow consumer advisory turned on + private BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("localhost"); + broker.setUseJmx(true); + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector("vm://localhost"); + + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setAdvisoryForSlowConsumers(true); + + policyMap.setDefaultEntry(defaultEntry); + + broker.setDestinationPolicy(policyMap); + broker.start(); + broker.waitUntilStarted(); + return broker; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicSubscriptionZeroPrefetchTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicSubscriptionZeroPrefetchTest.java new file mode 100644 index 0000000000..b9f0d5063f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TopicSubscriptionZeroPrefetchTest.java @@ -0,0 +1,116 @@ +/** + * 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.usecases; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTopic; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TopicSubscriptionZeroPrefetchTest { + + private static final String TOPIC_NAME = "slow.consumer"; + private Connection connection; + private Session session; + private ActiveMQTopic destination; + private MessageProducer producer; + private MessageConsumer consumer; + private BrokerService brokerService; + + @Before + public void setUp() throws Exception { + + brokerService = createBroker(); + + ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("vm://localhost"); + + activeMQConnectionFactory.setWatchTopicAdvisories(true); + connection = activeMQConnectionFactory.createConnection(); + connection.setClientID("ClientID-1"); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + destination = new ActiveMQTopic(TOPIC_NAME); + producer = session.createProducer(destination); + + connection.start(); + } + + /* + * test non durable topic subscription with prefetch set to zero + */ + @Test(timeout=60000) + public void testTopicConsumerPrefetchZero() throws Exception { + + ActiveMQTopic consumerDestination = new ActiveMQTopic(TOPIC_NAME + "?consumer.retroactive=true&consumer.prefetchSize=0"); + consumer = session.createConsumer(consumerDestination); + + // publish messages + Message txtMessage = session.createTextMessage("M"); + producer.send(txtMessage); + + Message consumedMessage = consumer.receiveNoWait(); + + Assert.assertNotNull("should have received a message the published message", consumedMessage); + } + + /* + * test durable topic subscription with prefetch zero + */ + @Test(timeout=60000) + public void testDurableTopicConsumerPrefetchZero() throws Exception { + + ActiveMQTopic consumerDestination = new ActiveMQTopic(TOPIC_NAME + "?consumer.prefetchSize=0"); + consumer = session.createDurableSubscriber(consumerDestination, "mysub1"); + + // publish messages + Message txtMessage = session.createTextMessage("M"); + producer.send(txtMessage); + + Message consumedMessage = consumer.receive(100); + + Assert.assertNotNull("should have received a message the published message", consumedMessage); + } + + @After + public void tearDown() throws Exception { + consumer.close(); + producer.close(); + session.close(); + connection.close(); + brokerService.stop(); + } + + // helper method to create a broker with slow consumer advisory turned on + private BrokerService createBroker() throws Exception { + BrokerService broker = new BrokerService(); + broker.setBrokerName("localhost"); + broker.setUseJmx(false); + broker.setDeleteAllMessagesOnStartup(true); + broker.addConnector("vm://localhost"); + broker.start(); + broker.waitUntilStarted(); + return broker; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransactionRollbackOrderTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransactionRollbackOrderTest.java new file mode 100644 index 0000000000..9567cea072 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransactionRollbackOrderTest.java @@ -0,0 +1,159 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Test case for AMQ-268 + * + * @author Paul Smith + * + */ +public final class TransactionRollbackOrderTest extends TestCase { + private static final Logger LOG = LoggerFactory.getLogger(TransactionRollbackOrderTest.class); + + private volatile String receivedText; + + private Session producerSession; + private Session consumerSession; + private Destination queue; + + private MessageProducer producer; + private MessageConsumer consumer; + private Connection connection; + private CountDownLatch latch = new CountDownLatch(1); + private int numMessages = 5; + private List msgSent = new ArrayList(); + private List msgCommitted = new ArrayList(); + private List msgRolledBack = new ArrayList(); + private List msgRedelivered = new ArrayList(); + + public void testTransaction() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + + connection = factory.createConnection(); + queue = new ActiveMQQueue(getClass().getName() + "." + getName()); + + producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerSession = connection.createSession(true, 0); + + producer = producerSession.createProducer(queue); + + consumer = consumerSession.createConsumer(queue); + consumer.setMessageListener(new MessageListener() { + + int msgCount; + int msgCommittedCount; + + public void onMessage(Message m) { + try { + msgCount++; + TextMessage tm = (TextMessage)m; + receivedText = tm.getText(); + + if (tm.getJMSRedelivered()) { + msgRedelivered.add(receivedText); + } + + LOG.info("consumer received message: " + receivedText + (tm.getJMSRedelivered() ? " ** Redelivered **" : "")); + if (msgCount == 3) { + msgRolledBack.add(receivedText); + consumerSession.rollback(); + LOG.info("[msg: " + receivedText + "] ** rolled back **"); + } else { + msgCommittedCount++; + msgCommitted.add(receivedText); + consumerSession.commit(); + LOG.info("[msg: " + receivedText + "] committed transaction "); + } + if (msgCommittedCount == numMessages) { + latch.countDown(); + } + } catch (JMSException e) { + try { + consumerSession.rollback(); + LOG.info("rolled back transaction"); + } catch (JMSException e1) { + LOG.info(e1.toString()); + e1.printStackTrace(); + } + LOG.info(e.toString()); + e.printStackTrace(); + } + } + }); + connection.start(); + + TextMessage tm = null; + try { + for (int i = 1; i <= numMessages; i++) { + tm = producerSession.createTextMessage(); + tm.setText("Hello " + i); + msgSent.add(tm.getText()); + producer.send(tm); + LOG.info("producer sent message: " + tm.getText()); + } + } catch (JMSException e) { + e.printStackTrace(); + } + + LOG.info("Waiting for latch"); + latch.await(); + + assertEquals(1, msgRolledBack.size()); + assertEquals(1, msgRedelivered.size()); + + LOG.info("msg RolledBack = " + msgRolledBack.get(0)); + LOG.info("msg Redelivered = " + msgRedelivered.get(0)); + + assertEquals(msgRolledBack.get(0), msgRedelivered.get(0)); + + assertEquals(numMessages, msgSent.size()); + assertEquals(numMessages, msgCommitted.size()); + + assertEquals(msgSent, msgCommitted); + + } + + protected void tearDown() throws Exception { + if (connection != null) { + LOG.info("Closing the connection"); + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransactionTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransactionTest.java new file mode 100644 index 0000000000..baee89ebaa --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransactionTest.java @@ -0,0 +1,122 @@ +/** + * 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.usecases; + +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author pragmasoft + * + */ +public final class TransactionTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(TransactionTest.class); + + private volatile String receivedText; + + private Session producerSession; + private Session consumerSession; + private Destination queue; + + private MessageProducer producer; + private MessageConsumer consumer; + private Connection connection; + private final CountDownLatch latch = new CountDownLatch(1); + + public void testTransaction() throws Exception { + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"); + connection = factory.createConnection(); + queue = new ActiveMQQueue(getClass().getName() + "." + getName()); + + producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerSession = connection.createSession(true, 0); + + producer = producerSession.createProducer(queue); + + consumer = consumerSession.createConsumer(queue); + consumer.setMessageListener(new MessageListener() { + + @Override + public void onMessage(Message m) { + try { + TextMessage tm = (TextMessage)m; + receivedText = tm.getText(); + latch.countDown(); + + LOG.info("consumer received message :" + receivedText); + consumerSession.commit(); + LOG.info("committed transaction"); + } catch (JMSException e) { + try { + consumerSession.rollback(); + LOG.info("rolled back transaction"); + } catch (JMSException e1) { + LOG.info(e1.toString()); + e1.printStackTrace(); + } + LOG.info(e.toString()); + e.printStackTrace(); + } + } + }); + + connection.start(); + + TextMessage tm = null; + try { + tm = producerSession.createTextMessage(); + tm.setText("Hello, " + new Date()); + producer.send(tm); + LOG.info("producer sent message :" + tm.getText()); + } catch (JMSException e) { + e.printStackTrace(); + } + + LOG.info("Waiting for latch"); + latch.await(2,TimeUnit.SECONDS); + assertNotNull(receivedText); + LOG.info("test completed, destination=" + receivedText); + } + + @Override + protected void tearDown() throws Exception { + if (connection != null) { + connection.close(); + } + super.tearDown(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransientQueueRedeliverTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransientQueueRedeliverTest.java new file mode 100644 index 0000000000..24fd890f75 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TransientQueueRedeliverTest.java @@ -0,0 +1,32 @@ +/** + * 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.usecases; + +import javax.jms.DeliveryMode; + +/** + * + */ +public class TransientQueueRedeliverTest extends TopicRedeliverTest { + + protected void setUp() throws Exception { + super.setUp(); + topic = false; + deliveryMode = DeliveryMode.NON_PERSISTENT; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerMessageNotSentToRemoteWhenNoConsumerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerMessageNotSentToRemoteWhenNoConsumerTest.java new file mode 100644 index 0000000000..3e97eb2223 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerMessageNotSentToRemoteWhenNoConsumerTest.java @@ -0,0 +1,131 @@ +/** + * 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.usecases; + +import java.net.URI; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.util.MessageIdList; + +public class TwoBrokerMessageNotSentToRemoteWhenNoConsumerTest extends JmsMultipleBrokersTestSupport { + protected static final int MESSAGE_COUNT = 100; + + /** + * BrokerA -> BrokerB + */ + public void testRemoteBrokerHasConsumer() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + + Thread.sleep(2000); + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT); + + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + assertEquals(MESSAGE_COUNT, msgsB.getMessageCount()); + + } + + /** + * BrokerA -> BrokerB + */ + public void testRemoteBrokerHasNoConsumer() throws Exception { + // Setup broker networks + bridgeBrokers("BrokerA", "BrokerB"); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + + msgsA.waitForMessagesToArrive(MESSAGE_COUNT); + + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + + } + + /** + * BrokerA -> BrokerB && BrokerB -> BrokerA + */ + public void testDuplexStaticRemoteBrokerHasNoConsumer() throws Exception { + // Setup broker networks + boolean dynamicOnly = true; + int networkTTL = 2; + boolean conduit = true; + bridgeBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduit); + bridgeBrokers("BrokerB", "BrokerA", dynamicOnly, networkTTL, conduit); + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + + Thread.sleep(2*1000); + + int messageCount = 2000; + // Send messages + sendMessages("BrokerA", dest, messageCount); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + + msgsA.waitForMessagesToArrive(messageCount); + + assertEquals(messageCount, msgsA.getMessageCount()); + + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + createBroker(new URI( + "broker:(tcp://localhost:61616)/BrokerA?persistent=false&useJmx=false")); + createBroker(new URI( + "broker:(tcp://localhost:61617)/BrokerB?persistent=false&useJmx=false")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerMulticastQueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerMulticastQueueTest.java new file mode 100644 index 0000000000..4f196fb7e7 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerMulticastQueueTest.java @@ -0,0 +1,267 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Arrays; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import junit.framework.Test; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.CombinationTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.xbean.XBeanBrokerFactory; + +public class TwoBrokerMulticastQueueTest extends CombinationTestSupport { + + public static final int MESSAGE_COUNT = 100; + public static final int BROKER_COUNT = 2; + public static final int CONSUMER_COUNT = 20; + + public String sendUri; + public String recvUri; + private BrokerService[] brokers; + private String groupId; + + public static Test suite() { + return suite(TwoBrokerMulticastQueueTest.class); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public void setUp() throws Exception { + groupId = getClass().getName()+"-"+System.currentTimeMillis(); + System.setProperty("groupId", groupId); + super.setAutoFail(true); + super.setUp(); + } + + public void tearDown() throws Exception { + if (brokers != null) { + for (int i = 0; i < BROKER_COUNT; i++) { + if (brokers[i] != null) { + brokers[i].stop(); + } + } + super.tearDown(); + } + } + + private void doSendReceiveTest() throws Exception { + Destination dest = new ActiveMQQueue("TEST.FOO"); + + ConnectionFactory sendFactory = createConnectionFactory(sendUri); + + Connection conn = createConnection(sendFactory); + sendMessages(conn, dest, MESSAGE_COUNT); + + Thread.sleep(500); + + ConnectionFactory recvFactory = createConnectionFactory(recvUri); + assertEquals(MESSAGE_COUNT, receiveMessages(createConnection(recvFactory), dest, 0)); + } + + private void doMultipleConsumersConnectTest() throws Exception { + Destination dest = new ActiveMQQueue("TEST.FOO"); + + ConnectionFactory sendFactory = createConnectionFactory(sendUri); + + Connection conn = createConnection(sendFactory); + sendMessages(conn, dest, MESSAGE_COUNT); + + Thread.sleep(500); + + ConnectionFactory recvFactory = createConnectionFactory(recvUri); + assertEquals(MESSAGE_COUNT, receiveMessages(createConnection(recvFactory), dest, 0)); + + for (int i = 0; i < (CONSUMER_COUNT - 1); i++) { + assertEquals(0, receiveMessages(createConnection(recvFactory), dest, 200)); + } + } + + public void initCombosForTestSendReceive() { + addCombinationValues("sendUri", new Object[] {"tcp://localhost:61616", "tcp://localhost:61617"}); + addCombinationValues("recvUri", new Object[] {"tcp://localhost:61616", "tcp://localhost:61617"}); + } + + public void testSendReceive() throws Exception { + createMulticastBrokerNetwork(); + doSendReceiveTest(); + } + + public void initCombosForTestMultipleConsumersConnect() { + addCombinationValues("sendUri", new Object[] {"tcp://localhost:61616", "tcp://localhost:61617"}); + addCombinationValues("recvUri", new Object[] {"tcp://localhost:61616", "tcp://localhost:61617"}); + } + + public void testMultipleConsumersConnect() throws Exception { + createMulticastBrokerNetwork(); + doMultipleConsumersConnectTest(); + } + + public void testSendReceiveUsingFailover() throws Exception { + sendUri = "failover:(tcp://localhost:61616,tcp://localhost:61617)"; + recvUri = "failover:(tcp://localhost:61616,tcp://localhost:61617)"; + createMulticastBrokerNetwork(); + doSendReceiveTest(); + } + + public void testMultipleConsumersConnectUsingFailover() throws Exception { + sendUri = "failover:(tcp://localhost:61616,tcp://localhost:61617)"; + recvUri = "failover:(tcp://localhost:61616,tcp://localhost:61617)"; + createMulticastBrokerNetwork(); + doMultipleConsumersConnectTest(); + } + + public void testSendReceiveUsingDiscovery() throws Exception { + sendUri = "discovery:multicast://default?group="+groupId; + recvUri = "discovery:multicast://default?group="+groupId; + createMulticastBrokerNetwork(); + doSendReceiveTest(); + } + + public void testMultipleConsumersConnectUsingDiscovery() throws Exception { + sendUri = "discovery:multicast://default?group="+groupId; + recvUri = "discovery:multicast://default?group="+groupId; + createMulticastBrokerNetwork(); + doMultipleConsumersConnectTest(); + } + + public void testSendReceiveUsingAutoAssignFailover() throws Exception { + sendUri = "failover:(discovery:multicast:default?group=//"+groupId+")"; + recvUri = "failover:(discovery:multicast:default?group=//"+groupId+")"; + createAutoAssignMulticastBrokerNetwork(); + doSendReceiveTest(); + } + + public void testMultipleConsumersConnectUsingAutoAssignFailover() throws Exception { + sendUri = "failover:(discovery:multicast:default?group=//"+groupId+")"; + recvUri = "failover:(discovery:multicast:default?group=//"+groupId+")"; + createAutoAssignMulticastBrokerNetwork(); + doMultipleConsumersConnectTest(); + } + + public void testSendReceiveUsingAutoAssignDiscovery() throws Exception { + sendUri = "discovery:multicast://default?group="+groupId; + recvUri = "discovery:multicast://default?group="+groupId; + createAutoAssignMulticastBrokerNetwork(); + doSendReceiveTest(); + } + + public void testMultipleConsumersConnectUsingAutoAssignDiscovery() throws Exception { + sendUri = "discovery:multicast://default?group="+groupId; + recvUri = "discovery:multicast://default?group="+groupId; + createAutoAssignMulticastBrokerNetwork(); + doMultipleConsumersConnectTest(); + } + + protected void createMulticastBrokerNetwork() throws Exception { + brokers = new BrokerService[BROKER_COUNT]; + for (int i = 0; i < BROKER_COUNT; i++) { + brokers[i] = createBroker("org/apache/activemq/usecases/multicast-broker-" + (i + 1) + ".xml"); + brokers[i].start(); + } + + // Let the brokers discover each other first + Thread.sleep(1000); + } + + protected void createAutoAssignMulticastBrokerNetwork() throws Exception { + brokers = new BrokerService[BROKER_COUNT]; + for (int i = 0; i < BROKER_COUNT; i++) { + brokers[i] = createBroker("org/apache/activemq/usecases/multicast-broker-auto.xml"); + brokers[i].start(); + } + + // Let the brokers discover each other first + Thread.sleep(1000); + } + + protected BrokerService createBroker(String uri) throws Exception { + return (new XBeanBrokerFactory()).createBroker(new URI(uri)); + } + + protected ConnectionFactory createConnectionFactory(String uri) { + return new ActiveMQConnectionFactory(uri); + } + + protected Connection createConnection(ConnectionFactory factory) throws JMSException { + Connection conn = factory.createConnection(); + return conn; + } + + protected int receiveMessages(Connection conn, Destination dest, int waitTime) throws JMSException, InterruptedException { + conn.start(); + MessageIdList list = new MessageIdList(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = sess.createConsumer(dest); + consumer.setMessageListener(list); + + if (waitTime > 0) { + Thread.sleep(waitTime); + } else { + list.waitForMessagesToArrive(MESSAGE_COUNT); + } + + conn.close(); + + return list.getMessageCount(); + } + + protected void sendMessages(Connection conn, Destination dest, int count) throws JMSException { + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer prod = sess.createProducer(dest); + + for (int i = 0; i < count; i++) { + prod.send(createTextMessage(sess, "Message " + i, 1024)); + } + + conn.close(); + } + + protected TextMessage createTextMessage(Session session, String initText, int messageSize) throws JMSException { + TextMessage msg = session.createTextMessage(); + + // Pad message text + if (initText.length() < messageSize) { + char[] data = new char[messageSize - initText.length()]; + Arrays.fill(data, '*'); + String str = new String(data); + msg.setText(initText + str); + + // Do not pad message text + } else { + msg.setText(initText); + } + + return msg; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkConnectorWildcardDynamicallyIncludedDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkConnectorWildcardDynamicallyIncludedDestinationTest.java new file mode 100644 index 0000000000..d6d0d65ad5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkConnectorWildcardDynamicallyIncludedDestinationTest.java @@ -0,0 +1,33 @@ +/** + * 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.usecases; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.NetworkConnector; + +public class TwoBrokerNetworkConnectorWildcardDynamicallyIncludedDestinationTest extends AbstractTwoBrokerNetworkConnectorWildcardIncludedDestinationTestSupport { + + protected void addIncludedDestination(NetworkConnector nc) { + nc.addExcludedDestination(ActiveMQDestination.createDestination("local.>", ActiveMQDestination.QUEUE_TYPE)); + nc.addExcludedDestination(ActiveMQDestination.createDestination("local.>", ActiveMQDestination.TOPIC_TYPE)); + nc.addExcludedDestination(ActiveMQDestination.createDestination("Consumer.*.local.>", ActiveMQDestination.QUEUE_TYPE)); + nc.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.QUEUE_TYPE)); + nc.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.TOPIC_TYPE)); + nc.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("Consumer.*.global.>", ActiveMQDestination.QUEUE_TYPE)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkConnectorWildcardStaticallyIncludedDestinationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkConnectorWildcardStaticallyIncludedDestinationTest.java new file mode 100644 index 0000000000..a8051db4f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkConnectorWildcardStaticallyIncludedDestinationTest.java @@ -0,0 +1,33 @@ +/** + * 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.usecases; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.NetworkConnector; + +public class TwoBrokerNetworkConnectorWildcardStaticallyIncludedDestinationTest extends AbstractTwoBrokerNetworkConnectorWildcardIncludedDestinationTestSupport { + + protected void addIncludedDestination(NetworkConnector nc) { + nc.addExcludedDestination(ActiveMQDestination.createDestination("local.>", ActiveMQDestination.QUEUE_TYPE)); + nc.addExcludedDestination(ActiveMQDestination.createDestination("local.>", ActiveMQDestination.TOPIC_TYPE)); + nc.addExcludedDestination(ActiveMQDestination.createDestination("Consumer.*.local.>", ActiveMQDestination.QUEUE_TYPE)); + nc.addStaticallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.QUEUE_TYPE)); + nc.addStaticallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.TOPIC_TYPE)); + nc.addStaticallyIncludedDestination(ActiveMQDestination.createDestination("Consumer.*.global.>", ActiveMQDestination.QUEUE_TYPE)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkLoadBalanceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkLoadBalanceTest.java new file mode 100644 index 0000000000..e773db288b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerNetworkLoadBalanceTest.java @@ -0,0 +1,77 @@ +/** + * 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.usecases; + +import java.net.URI; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.util.MessageIdList; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TwoBrokerNetworkLoadBalanceTest extends JmsMultipleBrokersTestSupport { + protected static final Logger LOG = LoggerFactory.getLogger(TwoBrokerNetworkLoadBalanceTest.class); + public void testLoadBalancing() throws Exception { + bridgeBrokers("BrokerA", "BrokerB"); + bridgeBrokers("BrokerB", "BrokerA"); + + startAllBrokers(); + waitForBridgeFormation(); + + // Setup destination + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + + // Setup consumers + MessageConsumer clientB = createConsumer("BrokerB", dest); + + // Send messages + sendMessages("BrokerA", dest, 5000); + + // Send messages + sendMessages("BrokerB", dest, 1000); + + // Get message count + final MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + final MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + + Wait.waitFor(new Wait.Condition() { + public boolean isSatisified() throws Exception { + return msgsA.getMessageCount() + msgsB.getMessageCount() == 6000; + }}); + + LOG.info("A got: " + msgsA.getMessageCount()); + LOG.info("B got: " + msgsB.getMessageCount()); + + assertTrue("B got is fair share: " + msgsB.getMessageCount(), msgsB.getMessageCount() > 2000); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + createBroker(new URI( + "broker:(tcp://localhost:61616)/BrokerA?persistent=false&useJmx=false")); + createBroker(new URI( + "broker:(tcp://localhost:61617)/BrokerB?persistent=false&useJmx=false")); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerQueueClientsReconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerQueueClientsReconnectTest.java new file mode 100644 index 0000000000..9adc2a3884 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerQueueClientsReconnectTest.java @@ -0,0 +1,606 @@ +/** + * 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.usecases; + +import java.net.URI; +import java.util.Collection; +import java.util.Iterator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.ActiveMQPrefetchPolicy; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerPlugin; +import org.apache.activemq.broker.BrokerPluginSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ProducerBrokerExchange; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.ConditionalNetworkBridgeFilterFactory; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TwoBrokerQueueClientsReconnectTest extends JmsMultipleBrokersTestSupport { + protected static final int MESSAGE_COUNT = 100; // Best if a factor of 100 + protected static final int PREFETCH_COUNT = 1; + protected static final int NETWORK_PREFETCH = 1; + private static final Logger LOG = LoggerFactory.getLogger(TwoBrokerQueueClientsReconnectTest.class); + + + protected int msgsClient1; + protected int msgsClient2; + protected String broker1; + protected String broker2; + + public void testClientAReceivesOnly() throws Exception { + broker1 = "BrokerA"; + broker2 = "BrokerB"; + + doOneClientReceivesOnly(); + } + + public void testClientBReceivesOnly() throws Exception { + broker1 = "BrokerB"; + broker2 = "BrokerA"; + + doOneClientReceivesOnly(); + } + + public void doOneClientReceivesOnly() throws Exception { + // allow immediate replay back to origin + applyRateLimitNetworkFilter(0); + + // Bridge brokers + bridgeBrokers(broker1, broker2); + bridgeBrokers(broker2, broker1); + + // Run brokers + startAllBrokers(); + + // Create queue + Destination dest = createDestination("TEST.FOO", false); + + // Create consumers + MessageConsumer client1 = createConsumer(broker1, dest); + MessageConsumer client2 = createConsumer(broker2, dest); + + // Give clients time to register with broker + Thread.sleep(500); + + // Always send messages to broker A + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Close the second client, messages should be sent to the first client + client2.close(); + + // Let the first client receive all messages + msgsClient1 += receiveAllMessages(client1); + client1.close(); + + // First client should have received 100 messages + assertEquals("Client for " + broker1 + " should have receive all messages.", MESSAGE_COUNT, msgsClient1); + } + + public void testClientAReceivesOnlyAfterReconnect() throws Exception { + broker1 = "BrokerA"; + broker2 = "BrokerB"; + + doOneClientReceivesOnlyAfterReconnect(); + } + + public void testClientBReceivesOnlyAfterReconnect() throws Exception { + broker1 = "BrokerB"; + broker2 = "BrokerA"; + + doOneClientReceivesOnlyAfterReconnect(); + } + + public void doOneClientReceivesOnlyAfterReconnect() throws Exception { + // allow immediate replay back to origin + applyRateLimitNetworkFilter(0); + + // Bridge brokers + bridgeBrokers(broker1, broker2); + bridgeBrokers(broker2, broker1); + + // Run brokers + startAllBrokers(); + + // Create queue + Destination dest = createDestination("TEST.FOO", false); + + // Create first consumer + MessageConsumer client1 = createConsumer(broker1, dest); + MessageConsumer client2 = createConsumer(broker2, dest); + + // Give clients time to register with broker + Thread.sleep(500); + + // Always send message to broker A + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Let the first client receive the first 20% of messages + msgsClient1 += receiveExactMessages(client1, (int)(MESSAGE_COUNT * 0.20)); + + // Disconnect the first client + client1.close(); + + // Create another client for the first broker + client1 = createConsumer(broker1, dest); + Thread.sleep(500); + + // Close the second client, messages should be sent to the first client + client2.close(); + + // Receive the rest of the messages + msgsClient1 += receiveAllMessages(client1); + client1.close(); + + // The first client should have received 100 messages + assertEquals("Client for " + broker1 + " should have received all messages.", MESSAGE_COUNT, msgsClient1); + } + + public void testTwoClientsReceiveClientADisconnects() throws Exception { + broker1 = "BrokerA"; + broker2 = "BrokerB"; + + doTwoClientsReceiveOneClientDisconnects(); + } + + public void testTwoClientsReceiveClientBDisconnects() throws Exception { + broker1 = "BrokerB"; + broker2 = "BrokerA"; + + doTwoClientsReceiveOneClientDisconnects(); + } + + public void doTwoClientsReceiveOneClientDisconnects() throws Exception { + // ensure all message do not flow across the network too quickly + applyRateLimitNetworkFilter(0.8 * MESSAGE_COUNT); + + // Bridge brokers + bridgeBrokers(broker1, broker2); + bridgeBrokers(broker2, broker1); + + // Run brokers + startAllBrokers(); + + // Create queue + Destination dest = createDestination("TEST.FOO", false); + + // Create first client + MessageConsumer client1 = createConsumer(broker1, dest); + MessageConsumer client2 = createConsumer(broker2, dest); + + // Give clients time to register with broker + Thread.sleep(500); + + // Always send messages to broker A + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + LOG.info("Let each client receive 20% of the messages - 40% total"); + msgsClient1 += receiveExactMessages(client1, (int)(MESSAGE_COUNT * 0.20)); + msgsClient2 += receiveExactMessages(client2, (int)(MESSAGE_COUNT * 0.20)); + + // Disconnect the first client + client1.close(); + + LOG.info("Let the second client receive the rest of the messages"); + msgsClient2 += receiveAllMessages(client2); + client2.close(); + + // First client should have received 20% of the messages + assertEquals("Client for " + broker1 + " should have received 20% of the messages.", (int)(MESSAGE_COUNT * 0.20), msgsClient1); + + // Second client should have received 80% of the messages + assertEquals("Client for " + broker2 + " should have received 80% of the messages.", (int)(MESSAGE_COUNT * 0.80), msgsClient2); + } + + public void testTwoClientsReceiveClientAReconnects() throws Exception { + broker1 = "BrokerA"; + broker2 = "BrokerB"; + + doTwoClientsReceiveOneClientReconnects(); + } + + public void testTwoClientsReceiveClientBReconnects() throws Exception { + broker1 = "BrokerB"; + broker2 = "BrokerA"; + + doTwoClientsReceiveOneClientReconnects(); + } + + public void doTwoClientsReceiveOneClientReconnects() throws Exception { + // ensure all message do not flow across the network too quickly + applyRateLimitNetworkFilter(0.2 * MESSAGE_COUNT); + + // Bridge brokers + bridgeBrokers(broker1, broker2); + bridgeBrokers(broker2, broker1); + + // Run brokers + startAllBrokers(); + + // Create queue + Destination dest = createDestination("TEST.FOO", false); + + // Create the first client + MessageConsumer client1 = createConsumer(broker1, dest); + MessageConsumer client2 = createConsumer(broker2, dest); + + // Give clients time to register with broker + Thread.sleep(500); + + // Always send messages to broker A + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Let each client receive 20% of the messages - 40% total + msgsClient1 += receiveExactMessages(client1, (int)(MESSAGE_COUNT * 0.20)); + msgsClient2 += receiveExactMessages(client2, (int)(MESSAGE_COUNT * 0.20)); + + LOG.info("msgsClient1=" + msgsClient1); + LOG.info("msgsClient2=" + msgsClient2); + + Thread.sleep(1000); + LOG.info("Disconnect the first client"); + client1.close(); + + LOG.info("Let the second client receive 20% more of the total messages"); + msgsClient2 += receiveExactMessages(client2, (int)(MESSAGE_COUNT * 0.20)); + + LOG.info("msgsClient2=" + msgsClient2); + + // Create another client for broker 1 + client1 = createConsumer(broker1, dest); + Thread.sleep(1000); + + // Let each client receive 20% of the messages - 40% total + msgsClient1 += receiveExactMessages(client1, (int)(MESSAGE_COUNT * 0.20)); + client1.close(); + LOG.info("new consumer addition, msgsClient1=" + msgsClient1); + + Thread.sleep(2000); + msgsClient2 += receiveExactMessages(client2, (int)(MESSAGE_COUNT * 0.20)); + client2.close(); + LOG.info("msgsClient2=" + msgsClient2); + + // First client should have received 40 messages + assertEquals("Client for " + broker1 + " should have received 40% of the messages.", (int)(MESSAGE_COUNT * 0.40), msgsClient1); + + // Second client should have received 60 messages + assertEquals("Client for " + broker2 + " should have received 60% of the messages.", (int)(MESSAGE_COUNT * 0.60), msgsClient2); + } + + private void applyRateLimitNetworkFilter(double rateLimit) { + ConditionalNetworkBridgeFilterFactory filterFactory = new ConditionalNetworkBridgeFilterFactory(); + filterFactory.setReplayWhenNoConsumers(true); + filterFactory.setRateLimit((int) rateLimit); + filterFactory.setRateDuration(1000); + + Collection brokerList = brokers.values(); + for (Iterator i = brokerList.iterator(); i.hasNext();) { + BrokerService broker = i.next().broker; + broker.getDestinationPolicy().getDefaultEntry().setNetworkBridgeFilterFactory(filterFactory); + } + } + + public void testTwoClientsReceiveTwoClientReconnects() throws Exception { + // ensure all message do not flow across the network too quickly + applyRateLimitNetworkFilter(0.5 * MESSAGE_COUNT); + + broker1 = "BrokerA"; + broker2 = "BrokerB"; + + // Bridge brokers + bridgeBrokers(broker1, broker2); + bridgeBrokers(broker2, broker1); + + // Run brokers + startAllBrokers(); + + // Create queue + Destination dest = createDestination("TEST.FOO", false); + + // Create the first client + MessageConsumer client1 = createConsumer(broker1, dest); + MessageConsumer client2 = createConsumer(broker2, dest); + + // Give clients time to register with broker + Thread.sleep(500); + + // Always send messages to broker A + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Let each client receive 20% of the messages - 40% total + msgsClient1 += receiveExactMessages(client1, (int)(MESSAGE_COUNT * 0.20)); + msgsClient2 += receiveExactMessages(client2, (int)(MESSAGE_COUNT * 0.20)); + + LOG.info("Disconnect both clients"); + client1.close(); + client2.close(); + + // Let each client receive 30% more of the total messages - 60% total + LOG.info("Serially create another two clients for each broker and consume in turn"); + client1 = createConsumer(broker1, dest); + msgsClient1 += receiveExactMessages(client1, (int)(MESSAGE_COUNT * 0.30)); + client1.close(); + + // the close will allow replay or the replay of the remaining messages + client2 = createConsumer(broker2, dest); + msgsClient2 += receiveExactMessages(client2, (int)(MESSAGE_COUNT * 0.30)); + client2.close(); + + // First client should have received 50% of the messages + assertEquals("Client for " + broker1 + " should have received 50% of the messages.", (int)(MESSAGE_COUNT * 0.50), msgsClient1); + + // Second client should have received 50% of the messages + assertEquals("Client for " + broker2 + " should have received 50% of the messages.", (int)(MESSAGE_COUNT * 0.50), msgsClient2); + } + + @SuppressWarnings("unchecked") + public void testDuplicateSend() throws Exception { + broker1 = "BrokerA"; + broker2 = "BrokerB"; + + // enable producer audit for the network connector, off by default b/c of interference with composite + // dests and virtual topics + brokers.get(broker2).broker.getTransportConnectors().get(0).setAuditNetworkProducers(true); + bridgeBrokers(broker1, broker2); + + final AtomicBoolean first = new AtomicBoolean(); + final CountDownLatch gotMessageLatch = new CountDownLatch(1); + + BrokerService brokerService = brokers.get(broker2).broker; + brokerService.setPersistent(true); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + @Override + public void send(final ProducerBrokerExchange producerExchange, + org.apache.activemq.command.Message messageSend) + throws Exception { + super.send(producerExchange, messageSend); + if (first.compareAndSet(false, true)) { + producerExchange.getConnectionContext().setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override + public void run() { + try { + LOG.info("Waiting for recepit"); + assertTrue("message received on time", gotMessageLatch.await(60, TimeUnit.SECONDS)); + LOG.info("Stopping connection post send and receive and multiple producers"); + producerExchange.getConnectionContext().getConnection().stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + } + }); + + // Run brokers + startAllBrokers(); + + waitForBridgeFormation(); + + // Create queue + Destination dest = createDestination("TEST.FOO", false); + + MessageConsumer client2 = createConsumer(broker2, dest); + + sendMessages("BrokerA", dest, 1); + + assertEquals("Client got message", 1, receiveExactMessages(client2, 1)); + client2.close(); + gotMessageLatch.countDown(); + + // message still pending on broker1 + assertEquals("messages message still there", 1, brokers.get(broker1).broker.getAdminView().getTotalMessageCount()); + + client2 = createConsumer(broker2, dest); + + LOG.info("Let the second client receive the rest of the messages"); + assertEquals("no duplicate message", 0, receiveAllMessages(client2)); + assertEquals("no duplicate message", 0, receiveAllMessages(client2)); + + assertEquals("no messages enqueued", 0, brokers.get(broker2).broker.getAdminView().getTotalMessageCount()); + assertTrue("no messages enqueued on origin", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == brokers.get(broker1).broker.getAdminView().getTotalMessageCount(); + } + })); + } + + @SuppressWarnings("unchecked") + public void testDuplicateSendWithNoAuditEnqueueCountStat() throws Exception { + broker1 = "BrokerA"; + broker2 = "BrokerB"; + + NetworkConnector networkConnector = bridgeBrokers(broker1, broker2); + + final AtomicBoolean first = new AtomicBoolean(); + final CountDownLatch gotMessageLatch = new CountDownLatch(1); + + BrokerService brokerService = brokers.get(broker2).broker; + brokerService.setPersistent(true); + brokerService.setDeleteAllMessagesOnStartup(true); + // disable concurrent dispatch otherwise store duplicate suppression will be skipped b/c cursor audit is already + // disabled so verification of stats will fail - ie: duplicate will be dispatched + ((KahaDBPersistenceAdapter)brokerService.getPersistenceAdapter()).setConcurrentStoreAndDispatchQueues(false); + brokerService.setPlugins(new BrokerPlugin[]{ + new BrokerPluginSupport() { + @Override + public void send(final ProducerBrokerExchange producerExchange, + org.apache.activemq.command.Message messageSend) + throws Exception { + super.send(producerExchange, messageSend); + if (first.compareAndSet(false, true)) { + producerExchange.getConnectionContext().setDontSendReponse(true); + Executors.newSingleThreadExecutor().execute(new Runnable() { + @Override + public void run() { + try { + LOG.info("Waiting for recepit"); + assertTrue("message received on time", gotMessageLatch.await(60, TimeUnit.SECONDS)); + LOG.info("Stopping connection post send and receive and multiple producers"); + producerExchange.getConnectionContext().getConnection().stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + } + }); + + // Create queue + ActiveMQDestination dest = createDestination("TEST.FOO", false); + + // statically include our destination + networkConnector.addStaticallyIncludedDestination(dest); + + // Run brokers + startAllBrokers(); + + waitForBridgeFormation(); + + sendMessages("BrokerA", dest, 1); + + // wait for broker2 to get the initial forward + Wait.waitFor(new Wait.Condition(){ + @Override + public boolean isSatisified() throws Exception { + return brokers.get(broker2).broker.getAdminView().getTotalMessageCount() == 1; + } + }); + + // message still pending on broker1 + assertEquals("messages message still there", 1, brokers.get(broker1).broker.getAdminView().getTotalMessageCount()); + + // allow the bridge to be shutdown and restarted + gotMessageLatch.countDown(); + + + // verify message is forwarded after restart + assertTrue("no messages enqueued on origin", Wait.waitFor(new Wait.Condition() { + @Override + public boolean isSatisified() throws Exception { + return 0 == brokers.get(broker1).broker.getAdminView().getTotalMessageCount(); + } + })); + + assertEquals("one messages pending", 1, brokers.get(broker2).broker.getAdminView().getTotalMessageCount()); + assertEquals("one messages enqueued", 1, brokers.get(broker2).broker.getDestination(dest).getDestinationStatistics().getEnqueues().getCount()); + } + + protected int receiveExactMessages(MessageConsumer consumer, int msgCount) throws Exception { + Message msg; + int i; + for (i = 0; i < msgCount; i++) { + msg = consumer.receive(4000); + if (msg == null) { + LOG.error("Consumer failed to receive exactly " + msgCount + " messages. Actual messages received is: " + i); + break; + } + } + + return i; + } + + protected int receiveAllMessages(MessageConsumer consumer) throws Exception { + int msgsReceived = 0; + + Message msg; + do { + msg = consumer.receive(1000); + if (msg != null) { + msgsReceived++; + } + } while (msg != null); + + return msgsReceived; + } + + @Override + protected MessageConsumer createConsumer(String brokerName, Destination dest) throws Exception { + Connection conn = createConnection(brokerName); + conn.start(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + return sess.createConsumer(dest); + } + + @Override + protected void configureBroker(BrokerService broker) { + PolicyMap policyMap = new PolicyMap(); + PolicyEntry defaultEntry = new PolicyEntry(); + defaultEntry.setEnableAudit(false); + policyMap.setDefaultEntry(defaultEntry); + broker.setDestinationPolicy(policyMap); + } + + @Override + protected NetworkConnector bridgeBrokers(BrokerService localBroker, BrokerService remoteBroker, boolean dynamicOnly, int networkTTL, boolean conduit, boolean failover) throws Exception { + NetworkConnector nc = super.bridgeBrokers(localBroker,remoteBroker, dynamicOnly, networkTTL, conduit, failover); + nc.setPrefetchSize(NETWORK_PREFETCH); + nc.setDecreaseNetworkConsumerPriority(true); + return nc; + } + + @Override + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + createBroker(new URI("broker:(tcp://localhost:61616)/BrokerA?persistent=false&useJmx=true")); + createBroker(new URI("broker:(tcp://localhost:61617)/BrokerB?persistent=false&useJmx=true")); + + // Configure broker connection factory + ActiveMQConnectionFactory factoryA; + ActiveMQConnectionFactory factoryB; + factoryA = (ActiveMQConnectionFactory)getConnectionFactory("BrokerA"); + factoryB = (ActiveMQConnectionFactory)getConnectionFactory("BrokerB"); + + // Set prefetch policy + ActiveMQPrefetchPolicy policy = new ActiveMQPrefetchPolicy(); + policy.setAll(PREFETCH_COUNT); + + factoryA.setPrefetchPolicy(policy); + factoryB.setPrefetchPolicy(policy); + + msgsClient1 = 0; + msgsClient2 = 0; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerQueueSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerQueueSendReceiveTest.java new file mode 100644 index 0000000000..d463c14cf5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerQueueSendReceiveTest.java @@ -0,0 +1,60 @@ +/** + * 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.usecases; + +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.network.DemandForwardingBridgeSupport; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class TwoBrokerQueueSendReceiveTest extends TwoBrokerTopicSendReceiveTest { + + private static final Logger LOG = LoggerFactory.getLogger(TwoBrokerQueueSendReceiveTest.class); + + protected void setUp() throws Exception { + topic = false; + super.setUp(); + } + + public void testReceiveOnXConsumersNoLeak() throws Exception { + consumer.close(); + sendMessages(); + for (int i=0; i brokers = new HashMap(); + + @Override + protected void setUp() throws Exception { + sendFactory = createSenderConnectionFactory(); + receiveFactory = createReceiverConnectionFactory(); + + // Give server enough time to setup, + // so we don't lose messages when connection fails + LOG.info("Waiting for brokers Initialize."); + Thread.sleep(5000); + LOG.info("Brokers should be initialized by now.. starting test."); + + super.setUp(); + } + + protected ActiveMQConnectionFactory createReceiverConnectionFactory() throws JMSException { + return createConnectionFactory("org/apache/activemq/usecases/receiver.xml", "receiver", + "vm://receiver"); + } + + protected ActiveMQConnectionFactory createSenderConnectionFactory() throws JMSException { + return createConnectionFactory("org/apache/activemq/usecases/sender.xml", "sender", "vm://sender"); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + for (Iterator iter = brokers.values().iterator(); iter.hasNext();) { + BrokerService broker = iter.next(); + ServiceSupport.dispose(broker); + iter.remove(); + } + } + + @Override + protected Connection createReceiveConnection() throws JMSException { + return receiveFactory.createConnection(); + } + + @Override + protected Connection createSendConnection() throws JMSException { + return sendFactory.createConnection(); + } + + protected ActiveMQConnectionFactory createConnectionFactory(String config, String brokerName, + String connectUrl) throws JMSException { + try { + BrokerFactoryBean brokerFactory = new BrokerFactoryBean(new ClassPathResource(config)); + brokerFactory.afterPropertiesSet(); + BrokerService broker = brokerFactory.getBroker(); + brokers.put(brokerName, broker); + + return new ActiveMQConnectionFactory(connectUrl); + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerTopicSendReceiveUsingJavaConfigurationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerTopicSendReceiveUsingJavaConfigurationTest.java new file mode 100644 index 0000000000..22544363e5 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerTopicSendReceiveUsingJavaConfigurationTest.java @@ -0,0 +1,77 @@ +/** + * 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.usecases; + +import javax.jms.JMSException; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; + +/** + * + */ +public class TwoBrokerTopicSendReceiveUsingJavaConfigurationTest extends TwoBrokerTopicSendReceiveTest { + BrokerService receiveBroker; + BrokerService sendBroker; + + protected ActiveMQConnectionFactory createReceiverConnectionFactory() throws JMSException { + try { + receiveBroker = new BrokerService(); + receiveBroker.setBrokerName("receiveBroker"); + receiveBroker.setUseJmx(false); + receiveBroker.setPersistent(false); + receiveBroker.addConnector("tcp://localhost:62002"); + receiveBroker.addNetworkConnector("static:failover:tcp://localhost:62001"); + receiveBroker.start(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:62002"); + return factory; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + protected ActiveMQConnectionFactory createSenderConnectionFactory() throws JMSException { + try { + sendBroker = new BrokerService(); + sendBroker.setBrokerName("sendBroker"); + sendBroker.setUseJmx(false); + sendBroker.setPersistent(false); + sendBroker.addConnector("tcp://localhost:62001"); + sendBroker.addNetworkConnector("static:failover:tcp://localhost:62002"); + sendBroker.start(); + + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:62001"); + return factory; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (sendBroker != null) { + sendBroker.stop(); + } + if (receiveBroker != null) { + receiveBroker.stop(); + } + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerTopicSendReceiveUsingTcpTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerTopicSendReceiveUsingTcpTest.java new file mode 100644 index 0000000000..933cfd6b2b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerTopicSendReceiveUsingTcpTest.java @@ -0,0 +1,80 @@ +/** + * 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.usecases; + +import javax.jms.JMSException; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.xbean.BrokerFactoryBean; +import org.springframework.core.io.ClassPathResource; + +/** + * + */ +public class TwoBrokerTopicSendReceiveUsingTcpTest extends TwoBrokerTopicSendReceiveTest { + private BrokerService receiverBroker; + private BrokerService senderBroker; + + protected void setUp() throws Exception { + BrokerFactoryBean brokerFactory; + + brokerFactory = new BrokerFactoryBean(new ClassPathResource("org/apache/activemq/usecases/receiver.xml")); + brokerFactory.afterPropertiesSet(); + receiverBroker = brokerFactory.getBroker(); + + brokerFactory = new BrokerFactoryBean(new ClassPathResource("org/apache/activemq/usecases/sender.xml")); + brokerFactory.afterPropertiesSet(); + senderBroker = brokerFactory.getBroker(); + + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + + if (receiverBroker != null) { + receiverBroker.stop(); + } + if (senderBroker != null) { + senderBroker.stop(); + } + } + + + protected ActiveMQConnectionFactory createReceiverConnectionFactory() throws JMSException { + try { + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(((TransportConnector)receiverBroker.getTransportConnectors().get(0)).getConnectUri()); + return fac; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + protected ActiveMQConnectionFactory createSenderConnectionFactory() throws JMSException { + try { + ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(((TransportConnector)senderBroker.getTransportConnectors().get(0)).getConnectUri()); + return fac; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerVirtualDestDinamicallyIncludedDestTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerVirtualDestDinamicallyIncludedDestTest.java new file mode 100644 index 0000000000..be175354c6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerVirtualDestDinamicallyIncludedDestTest.java @@ -0,0 +1,229 @@ +/** + * 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.usecases; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.DestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualDestination; +import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor; +import org.apache.activemq.broker.region.virtual.VirtualTopic; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.MessageIdList; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import java.io.File; +import java.io.IOException; +import java.net.URI; + +public class TwoBrokerVirtualDestDinamicallyIncludedDestTest extends JmsMultipleBrokersTestSupport { + protected static final int MESSAGE_COUNT = 10; + boolean dynamicOnly = true; + int networkTTL = 1; + boolean conduit = true; + boolean suppressDuplicateQueueSubscriptions = true; + boolean decreaseNetworkConsumerPriority = true; + + /** + * BrokerA -> BrokerB && BrokerB -> BrokerA + */ + public void testTopicDinamicallyIncludedBehavior() throws Exception { + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("test", true); + + // Setup consumers + MessageConsumer clientA = createConsumer("BrokerA", dest); + MessageConsumer clientB = createConsumer("BrokerB", dest); + + Thread.sleep(2*1000); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + msgsA.waitForMessagesToArrive(MESSAGE_COUNT); + assertEquals(MESSAGE_COUNT, msgsA.getMessageCount()); + + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + msgsB.waitForMessagesToArrive(MESSAGE_COUNT); + assertEquals(0, msgsB.getMessageCount()); + + } + + /** + * BrokerA -> BrokerB && BrokerB -> BrokerA + */ + public void testVirtualDestinationsDinamicallyIncludedBehavior1() throws Exception { + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("global.test", true); + + // Setup consumers + MessageConsumer clientB1 = createConsumer("BrokerB", dest); + MessageConsumer clientB2 = createConsumer("BrokerB", createDestination("Consumer.foo-bar.global.test", false)); + + Thread.sleep(2*1000); + + int messageCount = MESSAGE_COUNT; + // Send messages + sendMessages("BrokerA", dest, messageCount); + + // Get message count + MessageIdList msgsB1 = getConsumerMessages("BrokerB", clientB1); + msgsB1.waitForMessagesToArrive(messageCount); + assertEquals(messageCount, msgsB1.getMessageCount()); + + MessageIdList msgsB2 = getConsumerMessages("BrokerB", clientB2); + msgsB2.waitForMessagesToArrive(messageCount); + assertEquals(messageCount, msgsB2.getMessageCount()); + + } + + /** + * BrokerA -> BrokerB && BrokerB -> BrokerA + */ + public void testVirtualDestinationsDinamicallyIncludedBehavior2() throws Exception { + + startAllBrokers(); + + // Setup destination + Destination dest = createDestination("global.test", true); + + // Setup consumers + //MessageConsumer clientB1 = createConsumer("BrokerB", dest); + MessageConsumer clientB2 = createConsumer("BrokerB", createDestination("Consumer.foo-bar.global.test", false)); + + Thread.sleep(2*1000); + + // Send messages + sendMessages("BrokerA", dest, MESSAGE_COUNT); + + // Get message count + MessageIdList msgsB2 = getConsumerMessages("BrokerB", clientB2); + msgsB2.waitForMessagesToArrive(MESSAGE_COUNT); + assertEquals(MESSAGE_COUNT, msgsB2.getMessageCount()); + + } + + /** + * BrokerA -> BrokerB && BrokerB -> BrokerA + */ + public void testVirtualDestinationsDinamicallyIncludedBehavior3() throws Exception { + final String topic = "global.test"; + final String vq = "Consumer.foo." + topic; + + startAllBrokers(); + final int msgs1 = 1001; + final int msgs2 = 1456; + + // Setup destination + Destination tDest = createDestination(topic, true); + Destination vqDest = createDestination(vq, false); + + // Setup consumers + MessageConsumer clientB1t = createConsumer("BrokerA", tDest); + MessageConsumer clientB2t = createConsumer("BrokerB", tDest); + MessageConsumer clientB1vq = createConsumer("BrokerA", vqDest); + + Thread.sleep(2*1000); + + // Send messages + sendMessages("BrokerA", tDest, msgs1); + sendMessages("BrokerB", tDest, msgs2); + + Thread.sleep(5000); + + // Get message count + MessageIdList msgsB1t = getConsumerMessages("BrokerA", clientB1t); + msgsB1t.waitForMessagesToArrive(msgs1 + msgs2); + assertEquals(msgs1 + msgs2, msgsB1t.getMessageCount()); + MessageIdList msgsB2t = getConsumerMessages("BrokerB", clientB2t); + msgsB2t.waitForMessagesToArrive(msgs1 + msgs2); + assertEquals(msgs1 + msgs2, msgsB2t.getMessageCount()); + MessageIdList msgsB1vq = getConsumerMessages("BrokerA", clientB1vq); + msgsB1vq.waitForMessagesToArrive(msgs1 + msgs2); + assertEquals(msgs1 + msgs2, msgsB1vq.getMessageCount()); + + assertEquals(0, getQueueSize("BrokerA", (ActiveMQDestination)vqDest)); + assertEquals(0, getQueueSize("BrokerB", (ActiveMQDestination)vqDest)); + destroyAllBrokers(); + } + + public long getQueueSize(String broker, ActiveMQDestination destination) throws Exception { + BrokerItem bi = brokers.get(broker); + return bi.broker.getDestination(destination).getDestinationStatistics().getMessages().getCount(); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + String options = new String("?useJmx=false&deleteAllMessagesOnStartup=true"); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61616)/BrokerA" + options)); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61617)/BrokerB" + options)); + + // Setup broker networks + NetworkConnector nc1 = bridgeBrokers("BrokerA", "BrokerB", dynamicOnly, networkTTL, conduit); + nc1.setDecreaseNetworkConsumerPriority(decreaseNetworkConsumerPriority); + nc1.setSuppressDuplicateQueueSubscriptions(suppressDuplicateQueueSubscriptions); + nc1.addStaticallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.TOPIC_TYPE)); + //nc1.addExcludedDestination(ActiveMQDestination.createDestination("Consumer.*.global.>", ActiveMQDestination.QUEUE_TYPE)); + nc1.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.QUEUE_TYPE)); + nc1.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.TOPIC_TYPE)); + nc1.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("Consumer.*.global.>", ActiveMQDestination.QUEUE_TYPE)); + + NetworkConnector nc2 = bridgeBrokers("BrokerB", "BrokerA", dynamicOnly, networkTTL, conduit); + nc2.setDecreaseNetworkConsumerPriority(decreaseNetworkConsumerPriority); + nc2.setSuppressDuplicateQueueSubscriptions(suppressDuplicateQueueSubscriptions); + nc2.addStaticallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.TOPIC_TYPE)); + //nc2.addExcludedDestination(ActiveMQDestination.createDestination("Consumer.*.global.>", ActiveMQDestination.QUEUE_TYPE)); + nc2.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.QUEUE_TYPE)); + nc2.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("global.>", ActiveMQDestination.TOPIC_TYPE)); + nc2.addDynamicallyIncludedDestination(ActiveMQDestination.createDestination("Consumer.*.global.>", ActiveMQDestination.QUEUE_TYPE)); + } + + private BrokerService createAndConfigureBroker(URI uri) throws Exception { + BrokerService broker = createBroker(uri); + + configurePersistenceAdapter(broker); + + // make all topics virtual and consumers use the default prefix + VirtualDestinationInterceptor virtualDestinationInterceptor = new VirtualDestinationInterceptor(); + VirtualTopic vTopic = new VirtualTopic(); + vTopic.setLocal(true); + virtualDestinationInterceptor.setVirtualDestinations(new VirtualDestination[]{vTopic}); + DestinationInterceptor[] destinationInterceptors = new DestinationInterceptor[]{virtualDestinationInterceptor}; + broker.setDestinationInterceptors(destinationInterceptors); + return broker; + } + + protected void configurePersistenceAdapter(BrokerService broker) throws IOException { + File dataFileDir = new File("target/test-amq-data/kahadb/" + broker.getBrokerName()); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(dataFileDir); + kaha.deleteAllMessages(); + broker.setPersistenceAdapter(kaha); + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerVirtualTopicForwardingTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerVirtualTopicForwardingTest.java new file mode 100644 index 0000000000..0dc9e61e54 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoBrokerVirtualTopicForwardingTest.java @@ -0,0 +1,203 @@ +/** + * 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.usecases; + +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.Destination; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.store.kahadb.KahaDBStore; +import org.apache.activemq.util.MessageIdList; + +import javax.jms.MessageConsumer; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.LinkedList; + +import static org.apache.activemq.TestSupport.*; + +/** + * @author Christian Posta + */ +public class TwoBrokerVirtualTopicForwardingTest extends JmsMultipleBrokersTestSupport { + + public void testBridgeVirtualTopicQueues() throws Exception { + + bridgeAndConfigureBrokers("BrokerA", "BrokerB"); + startAllBrokers(); + waitForBridgeFormation(); + + MessageConsumer clientA = createConsumer("BrokerA", createDestination("Consumer.A.VirtualTopic.tempTopic", false)); + MessageConsumer clientB = createConsumer("BrokerB", createDestination("Consumer.B.VirtualTopic.tempTopic", false)); + + + // give a sec to let advisories propogate + Thread.sleep(500); + + ActiveMQQueue queueA = new ActiveMQQueue("Consumer.A.VirtualTopic.tempTopic"); + Destination destination = getDestination(brokers.get("BrokerA").broker, queueA); + assertEquals(1, destination.getConsumers().size()); + + ActiveMQQueue queueB = new ActiveMQQueue("Consumer.B.VirtualTopic.tempTopic"); + destination = getDestination(brokers.get("BrokerA").broker, queueB); + assertEquals(1, destination.getConsumers().size()); + + ActiveMQTopic virtualTopic = new ActiveMQTopic("VirtualTopic.tempTopic"); + assertNull(getDestination(brokers.get("BrokerA").broker, virtualTopic)); + assertNull(getDestination(brokers.get("BrokerB").broker, virtualTopic)); + + // send some messages + sendMessages("BrokerA", virtualTopic, 1); + + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + + msgsA.waitForMessagesToArrive(1); + msgsB.waitForMessagesToArrive(1); + + // ensure we don't get any more messages + Thread.sleep(2000); + + assertEquals(1, msgsA.getMessageCount()); + assertEquals(1, msgsB.getMessageCount()); + + } + + public void testDontBridgeQueuesWithOnlyQueueConsumers() throws Exception{ + dontBridgeVirtualTopicConsumerQueues("BrokerA", "BrokerB"); + + startAllBrokers(); + waitForBridgeFormation(); + + MessageConsumer clientA = createConsumer("BrokerA", createDestination("Consumer.A.VirtualTopic.tempTopic", false)); + MessageConsumer clientB = createConsumer("BrokerB", createDestination("Consumer.B.VirtualTopic.tempTopic", false)); + + + // give a sec to let advisories propogate + Thread.sleep(500); + + ActiveMQQueue queueA = new ActiveMQQueue("Consumer.A.VirtualTopic.tempTopic"); + Destination destination = getDestination(brokers.get("BrokerA").broker, queueA); + assertEquals(1, destination.getConsumers().size()); + + ActiveMQQueue queueB = new ActiveMQQueue("Consumer.B.VirtualTopic.tempTopic"); + destination = getDestination(brokers.get("BrokerA").broker, queueB); + assertNull(destination); + + ActiveMQTopic virtualTopic = new ActiveMQTopic("VirtualTopic.tempTopic"); + assertNull(getDestination(brokers.get("BrokerA").broker, virtualTopic)); + assertNull(getDestination(brokers.get("BrokerB").broker, virtualTopic)); + + // send some messages + sendMessages("BrokerA", virtualTopic, 1); + + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + + msgsA.waitForMessagesToArrive(1); + msgsB.waitForMessagesToArrive(0); + + // ensure we don't get any more messages + Thread.sleep(2000); + + assertEquals(1, msgsA.getMessageCount()); + assertEquals(0, msgsB.getMessageCount()); + } + + public void testDontBridgeQueuesWithBothTypesConsumers() throws Exception{ + dontBridgeVirtualTopicConsumerQueues("BrokerA", "BrokerB"); + + startAllBrokers(); + waitForBridgeFormation(); + + MessageConsumer clientA = createConsumer("BrokerA", createDestination("Consumer.A.VirtualTopic.tempTopic", false)); + MessageConsumer clientB = createConsumer("BrokerB", createDestination("Consumer.B.VirtualTopic.tempTopic", false)); + MessageConsumer clientC = createConsumer("BrokerB", createDestination("VirtualTopic.tempTopic", true)); + + + // give a sec to let advisories propogate + Thread.sleep(500); + + ActiveMQQueue queueA = new ActiveMQQueue("Consumer.A.VirtualTopic.tempTopic"); + Destination destination = getDestination(brokers.get("BrokerA").broker, queueA); + assertEquals(1, destination.getConsumers().size()); + + ActiveMQQueue queueB = new ActiveMQQueue("Consumer.B.VirtualTopic.tempTopic"); + destination = getDestination(brokers.get("BrokerA").broker, queueB); + assertNull(destination); + + ActiveMQTopic virtualTopic = new ActiveMQTopic("VirtualTopic.tempTopic"); + assertNotNull(getDestination(brokers.get("BrokerA").broker, virtualTopic)); + assertNotNull(getDestination(brokers.get("BrokerB").broker, virtualTopic)); + + // send some messages + sendMessages("BrokerA", virtualTopic, 1); + + MessageIdList msgsA = getConsumerMessages("BrokerA", clientA); + MessageIdList msgsB = getConsumerMessages("BrokerB", clientB); + + msgsA.waitForMessagesToArrive(1); + msgsB.waitForMessagesToArrive(1); + + // ensure we don't get any more messages + Thread.sleep(2000); + + assertEquals(1, msgsA.getMessageCount()); + assertEquals(1, msgsB.getMessageCount()); + } + + private void bridgeAndConfigureBrokers(String local, String remote) throws Exception { + NetworkConnector bridge = bridgeBrokers(local, remote); + bridge.setDecreaseNetworkConsumerPriority(true); + } + + private void dontBridgeVirtualTopicConsumerQueues(String local, String remote) throws Exception { + NetworkConnector bridge = bridgeBrokers(local, remote); + bridge.setDecreaseNetworkConsumerPriority(true); + + LinkedList excludedDestinations = new LinkedList(); + excludedDestinations.add(new ActiveMQQueue("Consumer.*.VirtualTopic.>")); + + bridge.setExcludedDestinations(excludedDestinations); + + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + String options = new String("?useJmx=false&deleteAllMessagesOnStartup=true"); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61616)/BrokerA" + options)); + createAndConfigureBroker(new URI("broker:(tcp://localhost:61617)/BrokerB" + options)); + } + + private BrokerService createAndConfigureBroker(URI uri) throws Exception { + BrokerService broker = createBroker(uri); + configurePersistenceAdapter(broker); + return broker; + } + + protected void configurePersistenceAdapter(BrokerService broker) throws IOException { + File dataFileDir = new File("target/test-amq-data/kahadb/" + broker.getBrokerName()); + KahaDBStore kaha = new KahaDBStore(); + kaha.setDirectory(dataFileDir); + broker.setPersistenceAdapter(kaha); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoMulticastDiscoveryBrokerTopicSendReceiveTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoMulticastDiscoveryBrokerTopicSendReceiveTest.java new file mode 100644 index 0000000000..f05f993c98 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoMulticastDiscoveryBrokerTopicSendReceiveTest.java @@ -0,0 +1,41 @@ +/** + * 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.usecases; + +import javax.jms.JMSException; + +import org.apache.activemq.ActiveMQConnectionFactory; + +/** + * reproduced: https://issues.apache.org/jira/browse/AMQ-4107 + */ +public class TwoMulticastDiscoveryBrokerTopicSendReceiveTest extends TwoBrokerTopicSendReceiveTest { + + protected ActiveMQConnectionFactory createReceiverConnectionFactory() throws JMSException { + return createConnectionFactory("org/apache/activemq/usecases/receiver-discovery.xml", "receiver", "vm://receiver"); + } + + protected ActiveMQConnectionFactory createSenderConnectionFactory() throws JMSException { + return createConnectionFactory("org/apache/activemq/usecases/sender-discovery.xml", "sender", "vm://sender"); + } + + protected void setUp() throws Exception{ + System.setProperty("groupId", getClass().getName()+"-"+System.currentTimeMillis()); + messageCount = 100000; + super.setUp(); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoSecureBrokerRequestReplyTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoSecureBrokerRequestReplyTest.java new file mode 100644 index 0000000000..dca3b08914 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/TwoSecureBrokerRequestReplyTest.java @@ -0,0 +1,89 @@ +/** + * 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.usecases; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQMessageConsumer; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.command.ActiveMQQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +import javax.jms.ConnectionFactory; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; + +public class TwoSecureBrokerRequestReplyTest extends JmsMultipleBrokersTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(TwoSecureBrokerRequestReplyTest.class); + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + + createBroker(new ClassPathResource("org/apache/activemq/usecases/sender-secured.xml")); + createBroker(new ClassPathResource("org/apache/activemq/usecases/receiver-secured.xml")); + } + + public void testRequestReply() throws Exception { + ActiveMQQueue requestReplyDest = new ActiveMQQueue("RequestReply"); + + startAllBrokers(); + waitForBridgeFormation(); + waitForMinTopicRegionConsumerCount("sender", 1); + waitForMinTopicRegionConsumerCount("receiver", 1); + + + ConnectionFactory factory = getConnectionFactory("sender"); + ActiveMQConnection conn = (ActiveMQConnection) factory.createConnection("system", "manager"); + conn.setWatchTopicAdvisories(false); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ConnectionFactory replyFactory = getConnectionFactory("receiver"); + for (int i = 0; i < 2000; i++) { + TemporaryQueue tempDest = session.createTemporaryQueue(); + MessageProducer producer = session.createProducer(requestReplyDest); + javax.jms.Message message = session.createTextMessage("req-" + i); + message.setJMSReplyTo(tempDest); + + ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer) session.createConsumer(tempDest); + producer.send(message); + + ActiveMQConnection replyConnection = (ActiveMQConnection) replyFactory.createConnection("system", "manager"); + replyConnection.setWatchTopicAdvisories(false); + replyConnection.start(); + Session replySession = replyConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + ActiveMQMessageConsumer replyConsumer = (ActiveMQMessageConsumer) replySession.createConsumer(requestReplyDest); + javax.jms.Message msg = replyConsumer.receive(10000); + assertNotNull("request message not null: " + i, msg); + MessageProducer replyProducer = replySession.createProducer(msg.getJMSReplyTo()); + replyProducer.send(session.createTextMessage("reply-" + i)); + replyConnection.close(); + + javax.jms.Message reply = consumer.receive(10000); + assertNotNull("reply message : " + i + ", to: " + tempDest + ", by consumer:" + consumer.getConsumerId(), reply); + consumer.close(); + tempDest.delete(); + LOG.info("message #" + i + " processed"); + } + + } + + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/UnlimitedEnqueueTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/UnlimitedEnqueueTest.java new file mode 100644 index 0000000000..f2c555596d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/UnlimitedEnqueueTest.java @@ -0,0 +1,137 @@ +/** + * 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.usecases; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.ResourceAllocationException; +import javax.jms.Session; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.FilePendingQueueMessageStoragePolicy; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.util.Wait; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertTrue; + +public class UnlimitedEnqueueTest { + + private static final Logger LOG = LoggerFactory.getLogger(UnlimitedEnqueueTest.class); + BrokerService brokerService = null; + final long numMessages = 5000; + final long numThreads = 10; + final int payLoadSize = 100*1024; + + @Test + public void testEnqueueIsOnlyLimitedByDisk() throws Exception { + ExecutorService executor = Executors.newCachedThreadPool(); + for (int i=0; i 1; + } + }, TimeUnit.MINUTES.toMillis(4))); + executor.shutdownNow(); + } + + @Before + public void createBrokerService() throws Exception { + brokerService = new BrokerService(); + brokerService.setDeleteAllMessagesOnStartup(true); + brokerService.setAdvisorySupport(false); + + // optional, reduce the usage limit so that spooling will occur faster + brokerService.getSystemUsage().getMemoryUsage().setLimit(10 * 1024 * 1024); + brokerService.getSystemUsage().getTempUsage().setLimit((numMessages * payLoadSize) + (1000 * payLoadSize)); + + PolicyMap policyMap = new PolicyMap(); + List entries = new ArrayList(); + PolicyEntry policy = new PolicyEntry(); + + // NB: ensure queue cursor limit is below the default 70% usage that the destination will use + // if they are the same, the queue memory limit and flow control will kick in first + policy.setCursorMemoryHighWaterMark(20); + + // on by default + //policy.setProducerFlowControl(true); + policy.setQueue(">"); + + // policy that will spool references to disk + policy.setPendingQueuePolicy(new FilePendingQueueMessageStoragePolicy()); + entries.add(policy); + policyMap.setPolicyEntries(entries); + brokerService.setDestinationPolicy(policyMap); + + brokerService.start(); + } + + public class Producer implements Runnable{ + + private final long numberOfMessages; + + public Producer(final long n){ + this.numberOfMessages = n; + } + + public void run(){ + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerService.getVmConnectorURI()); + try { + Connection conn = factory.createConnection(); + conn.start(); + byte[] bytes = new byte[payLoadSize]; + for (int i = 0; i < numberOfMessages; i++) { + Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue("test-queue"); + MessageProducer producer = session.createProducer(destination); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + BytesMessage message = session.createBytesMessage(); + message.writeBytes(bytes); + try { + producer.send(message); + } catch (ResourceAllocationException e) { + e.printStackTrace(); + } + session.close(); + } + } catch (JMSException e) { + // expect interrupted exception on shutdownNow + } + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/VerifyNetworkConsumersDisconnectTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/VerifyNetworkConsumersDisconnectTest.java new file mode 100644 index 0000000000..9eeb28c527 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/VerifyNetworkConsumersDisconnectTest.java @@ -0,0 +1,264 @@ +/** + * 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.usecases; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.net.URI; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.management.ObjectName; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.ManagementContext; +import org.apache.activemq.broker.jmx.QueueViewMBean; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VerifyNetworkConsumersDisconnectTest extends JmsMultipleBrokersTestSupport implements UncaughtExceptionHandler { + public static final int BROKER_COUNT = 3; + public static final int CONSUMER_COUNT = 5; + public static final int MESSAGE_COUNT = 0; + public static final boolean DUPLEX = false; + public static final boolean CONDUIT = true; + + public static final int NETWORK_TTL = 6; + private static final Logger LOG = LoggerFactory.getLogger(VerifyNetworkConsumersDisconnectTest.class); + public static final int TIMEOUT = 30000; + + protected Map consumerMap; + Map unhandledExceptions = new HashMap(); + + private void assertNoUnhandledExceptions() { + for( Entry e: unhandledExceptions.entrySet()) { + LOG.error("Thread:" + e.getKey() + " Had unexpected: " + e.getValue()); + } + assertTrue("There are no unhandled exceptions, see: log for detail on: " + unhandledExceptions, + unhandledExceptions.isEmpty()); + } + + public NetworkConnector bridge(String from, String to) throws Exception { + NetworkConnector networkConnector = bridgeBrokers(from, to, true, NETWORK_TTL, CONDUIT); + networkConnector.setSuppressDuplicateQueueSubscriptions(true); + networkConnector.setDecreaseNetworkConsumerPriority(true); + networkConnector.setDuplex(DUPLEX); + return networkConnector; + } + + /*why conduit proxy proxy consumers gets us in a knot w.r.t removal + DC-7 for CA-9, add DB-15, remove CA-9, add CB-8 + CB-8 add DC-7 + CB-8 - why not dead? + CB-8 for BA-6, add BD-15, remove BA-6 + BD-15 for DA-11, add DC-7 + */ + public void testConsumerOnEachBroker() throws Exception { + bridge("Broker0", "Broker1"); + if (!DUPLEX) bridge("Broker1", "Broker0"); + + bridge("Broker1", "Broker2"); + if (!DUPLEX) bridge("Broker2", "Broker1"); + + startAllBrokers(); + waitForBridgeFormation(brokers.get("Broker0").broker, 1, 0); + waitForBridgeFormation(brokers.get("Broker2").broker, 1, 0); + waitForBridgeFormation(brokers.get("Broker1").broker, 1, 0); + waitForBridgeFormation(brokers.get("Broker1").broker, 1, 1); + + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + for (int i = 0; i < BROKER_COUNT; i++) { + consumerMap.put("Consumer:" + i + ":0", createConsumer("Broker" + i, dest)); + } + + assertExactConsumersConnect("Broker0", 3, 1, TIMEOUT); + assertExactConsumersConnect("Broker2", 3, 1, TIMEOUT); + // piggy in the middle + assertExactConsumersConnect("Broker1", 3, 1, TIMEOUT); + + assertNoUnhandledExceptions(); + + LOG.info("Complete the mesh - 0->2"); + + // shorter route + NetworkConnector nc = bridge("Broker0", "Broker2"); + nc.setBrokerName("Broker0"); + nc.start(); + + + if (!DUPLEX) { + LOG.info("... complete the mesh - 2->0"); + nc = bridge("Broker2", "Broker0"); + nc.setBrokerName("Broker2"); + nc.start(); + } + + // wait for consumers to get propagated + for (int i = 0; i < BROKER_COUNT; i++) { + assertExactConsumersConnect("Broker" + i, 3, 1, TIMEOUT); + } + + // reverse order close + consumerMap.get("Consumer:" + 2 + ":0").close(); + TimeUnit.SECONDS.sleep(1); + consumerMap.get("Consumer:" + 1 + ":0").close(); + TimeUnit.SECONDS.sleep(1); + consumerMap.get("Consumer:" + 0 + ":0").close(); + + LOG.info("Check for no consumers.."); + for (int i = 0; i < BROKER_COUNT; i++) { + assertExactConsumersConnect("Broker" + i, 0, 0, TIMEOUT); + } + + } + + public void testXConsumerOnEachBroker() throws Exception { + bridge("Broker0", "Broker1"); + if (!DUPLEX) bridge("Broker1", "Broker0"); + + bridge("Broker1", "Broker2"); + if (!DUPLEX) bridge("Broker2", "Broker1"); + + startAllBrokers(); + + waitForBridgeFormation(brokers.get("Broker0").broker, 1, 0); + waitForBridgeFormation(brokers.get("Broker2").broker, 1, 0); + waitForBridgeFormation(brokers.get("Broker1").broker, 1, 0); + waitForBridgeFormation(brokers.get("Broker1").broker, 1, 1); + + Destination dest = createDestination("TEST.FOO", false); + + // Setup consumers + for (int i = 0; i < BROKER_COUNT; i++) { + for (int j=0; j< CONSUMER_COUNT; j++) + consumerMap.put("Consumer:" + i + ":" + j, createConsumer("Broker" + i, dest)); + } + + for (int i = 0; i < BROKER_COUNT; i++) { + assertExactConsumersConnect("Broker" + i, CONSUMER_COUNT + (BROKER_COUNT -1), 1, TIMEOUT); + } + + assertNoUnhandledExceptions(); + + LOG.info("Complete the mesh - 0->2"); + + // shorter route + NetworkConnector nc = bridge("Broker0", "Broker2"); + nc.setBrokerName("Broker0"); + nc.start(); + + waitForBridgeFormation(brokers.get("Broker0").broker, 1, 1); + + if (!DUPLEX) { + LOG.info("... complete the mesh - 2->0"); + nc = bridge("Broker2", "Broker0"); + nc.setBrokerName("Broker2"); + nc.start(); + } + + waitForBridgeFormation(brokers.get("Broker2").broker, 1, 1); + + for (int i = 0; i < BROKER_COUNT; i++) { + assertExactConsumersConnect("Broker" + i, CONSUMER_COUNT + (BROKER_COUNT -1), 1, TIMEOUT); + } + + // reverse order close + for (int i=0; i consumerIds = new LinkedList(); + for (ObjectName objectName : queueViewMBean.getSubscriptions()) { + consumerIds.add(objectName.getKeyProperty("consumerId")); + } + LOG.info("Sub IDs: " + consumerIds); + if (currentCount == count) { + stability.incrementAndGet(); + } else { + stability.set(0); + } + return stability.get() > numChecks; + } catch (Exception e) { + LOG.warn(": ", e); + return false; + } + } + }, timeout)); + } + + public void setUp() throws Exception { + super.setAutoFail(true); + super.setUp(); + + unhandledExceptions.clear(); + Thread.setDefaultUncaughtExceptionHandler(this); + + // Setup n brokers + for (int i = 0; i < BROKER_COUNT; i++) { + createBroker(new URI("broker:(tcp://localhost:6161" + i + ")/Broker" + i + "?persistent=false&useJmx=true&brokerId=Broker" + i)); + } + + consumerMap = new LinkedHashMap(); + } + + @Override + protected void configureBroker(BrokerService brokerService) { + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setExpireMessagesPeriod(0); + PolicyMap policyMap = new PolicyMap(); + policyMap.setDefaultEntry(policyEntry); + brokerService.setDestinationPolicy(policyMap); + } + + public void uncaughtException(Thread t, Throwable e) { + synchronized(unhandledExceptions) { + unhandledExceptions.put(t, e); + } + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/VirtualTopicNetworkClusterReactivationTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/VirtualTopicNetworkClusterReactivationTest.java new file mode 100644 index 0000000000..f6e002562c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/VirtualTopicNetworkClusterReactivationTest.java @@ -0,0 +1,176 @@ +/** + * 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.usecases; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.JmsMultipleBrokersTestSupport; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.region.policy.PolicyEntry; +import org.apache.activemq.broker.region.policy.PolicyMap; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.ConditionalNetworkBridgeFilterFactory; + +import javax.jms.*; +import java.net.URI; + +/** + * @author Christian Posta + */ +public class VirtualTopicNetworkClusterReactivationTest extends JmsMultipleBrokersTestSupport { + + private static final String BROKER_A = "brokerA"; + private static final String BROKER_B = "brokerB"; + private static final String BROKER_A_TRANSPORT_URL = "tcp://localhost:61616"; + private static final String BROKER_B_TRANSPORT_URL = "tcp://localhost:61617"; + private static final long DEFAULT_SLEEP_MS = 1000; + + private ActiveMQTopic topic = new ActiveMQTopic("VirtualTopic.FOO.TEST"); + private ActiveMQQueue queue = new ActiveMQQueue("Consumer.FOO.VirtualTopic.FOO.TEST"); + + + /** + * This test shows how to use pub/sub to mimic durable subscribers in a network of brokers. + * + * When using durable subscribers in a broker cluster, you can encounter a situation where a + * subscription gets orphaned on a broker when the client disconnects and reattaches to another + * broker in the cluster. Since the clientID/durableName only need to be unique within a single + * broker, it's possible to have a durable sub on multiple brokers in a cluster. + * + * FOR EXAMPLE: + * Broker A and B are networked together in both directions to form a full mesh. If durable + * subscriber 'foo' subscribes to failover(A,B) and ends up on B, and a producer on A, messages + * will be demand forwarded from A to B. But if the durable sub 'foo' disconnects from B, + * then reconnects to failover(A,B) but this time gets connected to A, the subscription on + * B will still be there are continue to receive messages (and possibly have missed messages + * sent there while gone) + * + * We can avoid all of this mess with virtual topics as seen below: + * + * + * @throws JMSException + */ + public void testDurableSubReconnectFromAtoB() throws JMSException { + // create consumer on broker B + ActiveMQConnectionFactory bConnFactory = new ActiveMQConnectionFactory(BROKER_B_TRANSPORT_URL+ "?jms.prefetchPolicy.queuePrefetch=0"); + Connection bConn = bConnFactory.createConnection(); + bConn.start(); + Session bSession = bConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer bSessionConsumer = bSession.createConsumer(queue); + + + // create producer on A + ActiveMQConnectionFactory aConnFactory = new ActiveMQConnectionFactory(BROKER_A_TRANSPORT_URL); + Connection aProducerConn = aConnFactory.createConnection(); + aProducerConn.start(); + + Session aProducerSession = aProducerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = aProducerSession.createProducer(topic); + produce(producer, aProducerSession, 5); + + // sleep for a sec to let the messages get bridged over to broker B + sleep(); + + // consumer on B has not consumed any messages, and for some reason goes away: + bSessionConsumer.close(); + bSession.close(); + bConn.close(); + + // let the bridge catch up + sleep(); + + // and now consumer reattaches to A and wants the messages that were sent to B + Connection aConsumerConn = aConnFactory.createConnection(); + aConsumerConn.start(); + Session aConsumerSession = aConsumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer aSessionConsumer = aConsumerSession.createConsumer(queue); + + sleep(); + + // they should all be there + consume(aSessionConsumer, 5); + + } + + + private void consume(MessageConsumer durable, int numMessagesExpected) throws JMSException { + for (int i = 0; i < numMessagesExpected; i++) { + Message message = durable.receive(1000); + assertNotNull(message); + TextMessage textMessage = (TextMessage) message; + System.out.println("received: " + textMessage.getText()); + assertEquals("message: " +i, textMessage.getText()); + } + } + + private void produce(MessageProducer producer, Session sess, int numMessages) throws JMSException { + for (int i = 0; i < numMessages; i++) { + producer.send(sess.createTextMessage("message: " + i)); + } + } + + @Override + protected void setUp() throws Exception { + maxSetupTime = 1000; + super.setAutoFail(true); + super.setUp(); + final String options = "?persistent=true&useJmx=false&deleteAllMessagesOnStartup=true"; + + BrokerService brokerServiceA = createBroker(new URI(String.format("broker:(%s)/%s%s", BROKER_A_TRANSPORT_URL, BROKER_A, options))); + brokerServiceA.setDestinationPolicy(buildPolicyMap()); + brokerServiceA.setDestinations(new ActiveMQDestination[]{queue}); + + BrokerService brokerServiceB = createBroker(new URI(String.format("broker:(%s)/%s%s", BROKER_B_TRANSPORT_URL, BROKER_B, options))); + brokerServiceB.setDestinationPolicy(buildPolicyMap()); + brokerServiceB.setDestinations(new ActiveMQDestination[]{queue}); + + + + // bridge brokers to each other statically (static: discovery) + bridgeBrokers(BROKER_A, BROKER_B); + bridgeBrokers(BROKER_B, BROKER_A); + + startAllBrokers(); + } + + private PolicyMap buildPolicyMap() { + PolicyMap policyMap = new PolicyMap(); + PolicyEntry policyEntry = new PolicyEntry(); + policyEntry.setOptimizedDispatch(true); + ConditionalNetworkBridgeFilterFactory networkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); + networkBridgeFilterFactory.setReplayWhenNoConsumers(true); + policyEntry.setNetworkBridgeFilterFactory(networkBridgeFilterFactory); + policyEntry.setEnableAudit(false); + policyMap.put(new ActiveMQQueue("Consumer.*.VirtualTopic.>"), policyEntry); + return policyMap; + } + + private void sleep() { + try { + Thread.sleep(DEFAULT_SLEEP_MS); + } catch (InterruptedException igonred) { + } + } + + private void sleep(int milliSecondTime) { + try { + Thread.sleep(milliSecondTime); + } catch (InterruptedException igonred) { + } + } +} \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/activemq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/activemq.xml new file mode 100644 index 0000000000..908b0cf2ee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/activemq.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1.xml new file mode 100644 index 0000000000..8a27d497dd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1A.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1A.xml new file mode 100644 index 0000000000..1d0c34e98d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1A.xml @@ -0,0 +1,193 @@ + + + + + + + + classpath:activemq-browse.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1B.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1B.xml new file mode 100644 index 0000000000..639b53d190 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker1B.xml @@ -0,0 +1,194 @@ + + + + + + + + + classpath:activemq-browse.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2.xml new file mode 100644 index 0000000000..0b34f0e4e6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2A.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2A.xml new file mode 100644 index 0000000000..0e2008cf61 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2A.xml @@ -0,0 +1,193 @@ + + + + + + + + classpath:activemq-browse.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2B.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2B.xml new file mode 100644 index 0000000000..2139cfb2d8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker2B.xml @@ -0,0 +1,195 @@ + + + + + + + + classpath:activemq-browse.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker3A.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker3A.xml new file mode 100644 index 0000000000..f879b1d679 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker3A.xml @@ -0,0 +1,192 @@ + + + + + + + + classpath:activemq-browse.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker3B.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker3B.xml new file mode 100644 index 0000000000..5301677145 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/browse-broker3B.xml @@ -0,0 +1,191 @@ + + + + + + + + classpath:activemq-browse.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-1.xml new file mode 100644 index 0000000000..a3123b6f33 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-1.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-2.xml new file mode 100644 index 0000000000..48cc372afb --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-2.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-auto.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-auto.xml new file mode 100644 index 0000000000..7c298d8c11 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/multicast-broker-auto.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker1.xml new file mode 100644 index 0000000000..0ed33d7bdd --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker1.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker2.xml new file mode 100644 index 0000000000..fd96b883bf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker2.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker3.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker3.xml new file mode 100644 index 0000000000..3438feec17 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rebalance-broker3.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-activecluster.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-activecluster.xml new file mode 100644 index 0000000000..719e6d2cef --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-activecluster.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-discovery.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-discovery.xml new file mode 100644 index 0000000000..9ad519d674 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-discovery.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-duplex.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-duplex.xml new file mode 100644 index 0000000000..9b4750fd69 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-duplex.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-http.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-http.xml new file mode 100644 index 0000000000..06aba93e2f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-http.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-secured.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-secured.xml new file mode 100644 index 0000000000..33b5a2ee1a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-secured.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-zeroconf.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-zeroconf.xml new file mode 100644 index 0000000000..470fe35e24 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver-zeroconf.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver.xml new file mode 100644 index 0000000000..50d2db2751 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/receiver.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker1.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker1.xml new file mode 100644 index 0000000000..20a974cc69 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker1.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker2.xml new file mode 100644 index 0000000000..700095e713 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker2.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker3.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker3.xml new file mode 100644 index 0000000000..f3ee99ded0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker3.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker4.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker4.xml new file mode 100644 index 0000000000..96b778ab7d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/replication-broker4.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-A.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-A.xml new file mode 100644 index 0000000000..bc367f7a02 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-A.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-B.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-B.xml new file mode 100644 index 0000000000..524a338fc4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-B.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-C.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-C.xml new file mode 100644 index 0000000000..8c5c810385 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-C.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-D.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-D.xml new file mode 100644 index 0000000000..8a2de52bfe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/rerouting-activemq-D.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-activecluster.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-activecluster.xml new file mode 100644 index 0000000000..38f7a3cb27 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-activecluster.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-discovery.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-discovery.xml new file mode 100644 index 0000000000..5319b39dd9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-discovery.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-duplex.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-duplex.xml new file mode 100644 index 0000000000..a8195c0745 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-duplex.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-http.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-http.xml new file mode 100644 index 0000000000..b5f5cea508 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-http.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-secured.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-secured.xml new file mode 100644 index 0000000000..0eb9562d33 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-secured.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-zeroconf.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-zeroconf.xml new file mode 100644 index 0000000000..aa695566af --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender-zeroconf.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender.xml new file mode 100644 index 0000000000..c83d89b63c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/usecases/sender.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ConsumerThread.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ConsumerThread.java new file mode 100644 index 0000000000..6b4bad2a8b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ConsumerThread.java @@ -0,0 +1,80 @@ +/** + * 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.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; + +public class ConsumerThread extends Thread { + + private static final Logger LOG = LoggerFactory.getLogger(ConsumerThread.class); + + int messageCount = 1000; + int received = 0; + Destination dest; + Session sess; + boolean breakOnNull = true; + + public ConsumerThread(Session sess, Destination dest) { + this.dest = dest; + this.sess = sess; + } + + @Override + public void run() { + MessageConsumer consumer = null; + + try { + consumer = sess.createConsumer(dest); + while (received < messageCount) { + Message msg = consumer.receive(3000); + if (msg != null) { + LOG.info("Received " + received + ": " + ((TextMessage)msg).getText()); + received++; + } else { + if (breakOnNull) { + break; + } + } + } + } catch (JMSException e) { + e.printStackTrace(); + } finally { + if (consumer != null) { + try { + consumer.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + } + + public int getReceived() { + return received; + } + + public void setMessageCount(int messageCount) { + this.messageCount = messageCount; + } + + public void setBreakOnNull(boolean breakOnNull) { + this.breakOnNull = breakOnNull; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/DefaultTestAppender.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/DefaultTestAppender.java new file mode 100644 index 0000000000..97ca4b3f5d --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/DefaultTestAppender.java @@ -0,0 +1,83 @@ +/** + * 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.util; + +import org.apache.log4j.Appender; +import org.apache.log4j.Layout; +import org.apache.log4j.spi.ErrorHandler; +import org.apache.log4j.spi.Filter; + +public abstract class DefaultTestAppender implements Appender { + + String name = this.getClass().getSimpleName(); + + @Override + public void addFilter(Filter newFilter) { + + } + + @Override + public Filter getFilter() { + return null; + } + + @Override + public void clearFilters() { + + } + + @Override + public void close() { + + } + + @Override + public String getName() { + return name; + } + + @Override + public void setErrorHandler(ErrorHandler errorHandler) { + + } + + @Override + public ErrorHandler getErrorHandler() { + return null; + } + + @Override + public void setLayout(Layout layout) { + + } + + @Override + public Layout getLayout() { + return null; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public boolean requiresLayout() { + return false; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/LinkedNodeTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/LinkedNodeTest.java new file mode 100644 index 0000000000..86c526213c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/LinkedNodeTest.java @@ -0,0 +1,173 @@ +/** + * 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.util; + +import junit.framework.TestCase; + +/** + * @author chirino + */ +public class LinkedNodeTest extends TestCase { + + static class IntLinkedNode extends LinkedNode { + public final int v; + + public IntLinkedNode(int v) { + this.v = v; + }; + + @Override + public String toString() { + return "" + v; + } + } + + IntLinkedNode i1 = new IntLinkedNode(1); + IntLinkedNode i2 = new IntLinkedNode(2); + IntLinkedNode i3 = new IntLinkedNode(3); + IntLinkedNode i4 = new IntLinkedNode(4); + IntLinkedNode i5 = new IntLinkedNode(5); + IntLinkedNode i6 = new IntLinkedNode(6); + + public void testLinkAfter() { + + i1.linkAfter(i2.linkAfter(i3)); + // Order should be 1,2,3 + + assertTrue(i1.getNext() == i2); + assertTrue(i1.getNext().getNext() == i3); + assertNull(i1.getNext().getNext().getNext()); + + assertTrue(i3.getPrevious() == i2); + assertTrue(i3.getPrevious().getPrevious() == i1); + assertNull(i3.getPrevious().getPrevious().getPrevious()); + + assertTrue(i1.isHeadNode()); + assertFalse(i1.isTailNode()); + assertFalse(i2.isHeadNode()); + assertFalse(i2.isTailNode()); + assertTrue(i3.isTailNode()); + assertFalse(i3.isHeadNode()); + + i1.linkAfter(i4.linkAfter(i5)); + + // Order should be 1,4,5,2,3 + + assertTrue(i1.getNext() == i4); + assertTrue(i1.getNext().getNext() == i5); + assertTrue(i1.getNext().getNext().getNext() == i2); + assertTrue(i1.getNext().getNext().getNext().getNext() == i3); + assertNull(i1.getNext().getNext().getNext().getNext().getNext()); + + assertTrue(i3.getPrevious() == i2); + assertTrue(i3.getPrevious().getPrevious() == i5); + assertTrue(i3.getPrevious().getPrevious().getPrevious() == i4); + assertTrue(i3.getPrevious().getPrevious().getPrevious().getPrevious() == i1); + assertNull(i3.getPrevious().getPrevious().getPrevious().getPrevious().getPrevious()); + + assertTrue(i1.isHeadNode()); + assertFalse(i1.isTailNode()); + assertFalse(i4.isHeadNode()); + assertFalse(i4.isTailNode()); + assertFalse(i5.isHeadNode()); + assertFalse(i5.isTailNode()); + assertFalse(i2.isHeadNode()); + assertFalse(i2.isTailNode()); + assertTrue(i3.isTailNode()); + assertFalse(i3.isHeadNode()); + + } + + public void testLinkBefore() { + + i3.linkBefore(i2.linkBefore(i1)); + + assertTrue(i1.getNext() == i2); + assertTrue(i1.getNext().getNext() == i3); + assertNull(i1.getNext().getNext().getNext()); + + assertTrue(i3.getPrevious() == i2); + assertTrue(i3.getPrevious().getPrevious() == i1); + assertNull(i3.getPrevious().getPrevious().getPrevious()); + + assertTrue(i1.isHeadNode()); + assertFalse(i1.isTailNode()); + assertFalse(i2.isHeadNode()); + assertFalse(i2.isTailNode()); + assertTrue(i3.isTailNode()); + assertFalse(i3.isHeadNode()); + + i2.linkBefore(i5.linkBefore(i4)); + + // Order should be 1,4,5,2,3 + + assertTrue(i1.getNext() == i4); + assertTrue(i1.getNext().getNext() == i5); + assertTrue(i1.getNext().getNext().getNext() == i2); + assertTrue(i1.getNext().getNext().getNext().getNext() == i3); + assertNull(i1.getNext().getNext().getNext().getNext().getNext()); + + assertTrue(i3.getPrevious() == i2); + assertTrue(i3.getPrevious().getPrevious() == i5); + assertTrue(i3.getPrevious().getPrevious().getPrevious() == i4); + assertTrue(i3.getPrevious().getPrevious().getPrevious().getPrevious() == i1); + assertNull(i3.getPrevious().getPrevious().getPrevious().getPrevious().getPrevious()); + + assertTrue(i1.isHeadNode()); + assertFalse(i1.isTailNode()); + assertFalse(i4.isHeadNode()); + assertFalse(i4.isTailNode()); + assertFalse(i5.isHeadNode()); + assertFalse(i5.isTailNode()); + assertFalse(i2.isHeadNode()); + assertFalse(i2.isTailNode()); + assertTrue(i3.isTailNode()); + assertFalse(i3.isHeadNode()); + + } + + public void testUnlink() { + + i1.linkAfter(i2.linkAfter(i3)); + i3.linkAfter(i4); + i1.linkBefore(i5); + i1.linkAfter(i6); + + // Order should be 5,1,6,2,3,4 + i4.unlink(); + i5.unlink(); + i6.unlink(); + + // Order should be 1,2,3 + + assertTrue(i1.getNext() == i2); + assertTrue(i1.getNext().getNext() == i3); + assertNull(i1.getNext().getNext().getNext()); + + assertTrue(i3.getPrevious() == i2); + assertTrue(i3.getPrevious().getPrevious() == i1); + assertNull(i3.getPrevious().getPrevious().getPrevious()); + + assertTrue(i1.isHeadNode()); + assertFalse(i1.isTailNode()); + assertFalse(i2.isHeadNode()); + assertFalse(i2.isTailNode()); + assertTrue(i3.isTailNode()); + assertFalse(i3.isHeadNode()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/MessageIdList.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/MessageIdList.java new file mode 100644 index 0000000000..7140a8650c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/MessageIdList.java @@ -0,0 +1,273 @@ +/** + * 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.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A simple container of messages for performing testing and rendezvous style + * code. You can use this class a {@link MessageListener} and then make + * assertions about how many messages it has received allowing a certain maximum + * amount of time to ensure that the test does not hang forever. Also you can + * chain these instances together with the {@link #setParent(MessageListener)} + * method so that you can aggregate the total number of messages consumed across + * a number of consumers. + * + * + */ +public class MessageIdList extends Assert implements MessageListener { + + private static final Logger LOG = LoggerFactory.getLogger(MessageIdList.class); + + private final List messageIds = new ArrayList(); + private final Object semaphore; + private boolean verbose; + private MessageListener parent; + private long maximumDuration = 15000L; + private long processingDelay; + + private CountDownLatch countDownLatch; + + public MessageIdList() { + this(new Object()); + } + + public MessageIdList(Object semaphore) { + this.semaphore = semaphore; + } + + @Override + public boolean equals(Object that) { + if (that instanceof MessageIdList) { + MessageIdList thatList = (MessageIdList)that; + return getMessageIds().equals(thatList.getMessageIds()); + } + return false; + } + + @Override + public int hashCode() { + synchronized (semaphore) { + return messageIds.hashCode() + 1; + } + } + + @Override + public String toString() { + synchronized (semaphore) { + return messageIds.toString(); + } + } + + /** + * @return all the messages on the list so far, clearing the buffer + */ + public List flushMessages() { + synchronized (semaphore) { + List answer = new ArrayList(messageIds); + messageIds.clear(); + return answer; + } + } + + public synchronized List getMessageIds() { + synchronized (semaphore) { + return new ArrayList(messageIds); + } + } + + @Override + public void onMessage(Message message) { + String id = null; + try { + id = message.getJMSMessageID(); + synchronized (semaphore) { + messageIds.add(id); + semaphore.notifyAll(); + } + if (countDownLatch != null) { + countDownLatch.countDown(); + } + if (LOG.isDebugEnabled()) { + LOG.debug("Received message: " + message); + } + } catch (JMSException e) { + e.printStackTrace(); + } + if (parent != null) { + parent.onMessage(message); + } + if (processingDelay > 0) { + try { + Thread.sleep(processingDelay); + } catch (InterruptedException e) { + } + } + } + + public int getMessageCount() { + synchronized (semaphore) { + return messageIds.size(); + } + } + + public void waitForMessagesToArrive(int messageCount) { + LOG.info("Waiting for " + messageCount + " message(s) to arrive"); + + long start = System.currentTimeMillis(); + + for (int i = 0; i < messageCount; i++) { + try { + if (hasReceivedMessages(messageCount)) { + break; + } + long duration = System.currentTimeMillis() - start; + if (duration >= maximumDuration) { + break; + } + synchronized (semaphore) { + semaphore.wait(maximumDuration - duration); + } + } catch (InterruptedException e) { + LOG.info("Caught: " + e); + } + } + long end = System.currentTimeMillis() - start; + + LOG.info("End of wait for " + end + " millis and received: " + getMessageCount() + " messages"); + } + + /** + * Performs a testing assertion that the correct number of messages have + * been received without waiting + * + * @param messageCount + */ + public void assertMessagesReceivedNoWait(int messageCount) { + assertEquals("expected number of messages when received", messageCount, getMessageCount()); + } + + /** + * Performs a testing assertion that the correct number of messages have + * been received waiting for the messages to arrive up to a fixed amount of + * time. + * + * @param messageCount + */ + public void assertMessagesReceived(int messageCount) { + waitForMessagesToArrive(messageCount); + + assertMessagesReceivedNoWait(messageCount); + } + + /** + * Asserts that there are at least the given number of messages received + * without waiting. + */ + public void assertAtLeastMessagesReceived(int messageCount) { + int actual = getMessageCount(); + assertTrue("at least: " + messageCount + " messages received. Actual: " + actual, actual >= messageCount); + } + + /** + * Asserts that there are at most the number of messages received without + * waiting + * + * @param messageCount + */ + public void assertAtMostMessagesReceived(int messageCount) { + int actual = getMessageCount(); + assertTrue("at most: " + messageCount + " messages received. Actual: " + actual, actual <= messageCount); + } + + public boolean hasReceivedMessage() { + return getMessageCount() == 0; + } + + public boolean hasReceivedMessages(int messageCount) { + return getMessageCount() >= messageCount; + } + + public boolean isVerbose() { + return verbose; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public MessageListener getParent() { + return parent; + } + + /** + * Allows a parent listener to be specified such as to aggregate messages + * consumed across consumers + */ + public void setParent(MessageListener parent) { + this.parent = parent; + } + + /** + * @return the maximumDuration + */ + public long getMaximumDuration() { + return this.maximumDuration; + } + + /** + * @param maximumDuration the maximumDuration to set + */ + public void setMaximumDuration(long maximumDuration) { + this.maximumDuration = maximumDuration; + } + + public void setCountDownLatch(CountDownLatch countDownLatch) { + this.countDownLatch = countDownLatch; + } + + /** + * Gets the amount of time the message listener will spend sleeping to + * simulate a processing delay. + * + * @return + */ + public long getProcessingDelay() { + return processingDelay; + } + + /** + * Sets the amount of time the message listener will spend sleeping to + * simulate a processing delay. + * + * @param processingDelay + */ + public void setProcessingDelay(long processingDelay) { + this.processingDelay = processingDelay; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ProducerThread.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ProducerThread.java new file mode 100644 index 0000000000..c7cf90dbcf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ProducerThread.java @@ -0,0 +1,82 @@ +/** + * 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.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; + +public class ProducerThread extends Thread { + + private static final Logger LOG = LoggerFactory.getLogger(ProducerThread.class); + + int messageCount = 1000; + Destination dest; + protected Session sess; + int sleep = 0; + int sentCount = 0; + + public ProducerThread(Session sess, Destination dest) { + this.dest = dest; + this.sess = sess; + } + + public void run() { + MessageProducer producer = null; + try { + producer = sess.createProducer(dest); + for (sentCount = 0; sentCount < messageCount; sentCount++) { + producer.send(createMessage(sentCount)); + LOG.info("Sent 'test message: " + sentCount + "'"); + if (sleep > 0) { + Thread.sleep(sleep); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (producer != null) { + try { + producer.close(); + } catch (JMSException e) { + e.printStackTrace(); + } + } + } + } + + protected Message createMessage(int i) throws Exception { + return sess.createTextMessage("test message: " + i); + } + + public void setMessageCount(int messageCount) { + this.messageCount = messageCount; + } + + public void setSleep(int sleep) { + this.sleep = sleep; + } + + public int getMessageCount() { + return messageCount; + } + + public int getSentCount() { + return sentCount; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ReflectionSupportTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ReflectionSupportTest.java new file mode 100644 index 0000000000..89759219f2 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/ReflectionSupportTest.java @@ -0,0 +1,115 @@ +/** + * 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.util; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; + +public class ReflectionSupportTest extends TestCase { + + List favorites = new ArrayList(); + String favoritesString = "[queue://test, topic://test]"; + List nonFavorites = new ArrayList(); + String nonFavoritesString = "[topic://test1]"; + + public void setUp() { + favorites.add(new ActiveMQQueue("test")); + favorites.add(new ActiveMQTopic("test")); + nonFavorites.add(new ActiveMQTopic("test1")); + } + + public void testSetProperties() throws URISyntaxException { + SimplePojo pojo = new SimplePojo(); + HashMap map = new HashMap(); + map.put("age", "27"); + map.put("name", "Hiram"); + map.put("enabled", "true"); + map.put("uri", "test://value"); + map.put("favorites", favoritesString); + map.put("nonFavorites", nonFavoritesString); + map.put("others", null); + map.put("systems", "windows,mac"); + + IntrospectionSupport.setProperties(pojo, map); + + assertEquals(27, pojo.getAge()); + assertEquals("Hiram", pojo.getName()); + assertEquals(true, pojo.isEnabled()); + assertEquals(new URI("test://value"), pojo.getUri()); + assertEquals(favorites, pojo.getFavorites()); + assertEquals(nonFavorites, pojo.getNonFavorites()); + assertNull(pojo.getOthers()); + assertEquals("windows", pojo.getSystems()[0]); + assertEquals("mac", pojo.getSystems()[1]); + } + + public void testGetProperties() { + SimplePojo pojo = new SimplePojo(); + pojo.setAge(31); + pojo.setName("Dejan"); + pojo.setEnabled(true); + pojo.setFavorites(favorites); + pojo.setNonFavorites(nonFavorites); + pojo.setOthers(null); + pojo.setSystems(new String[]{"windows", "mac"}); + + Properties props = new Properties(); + + IntrospectionSupport.getProperties(pojo, props, null); + + assertEquals("Dejan", props.get("name")); + assertEquals("31", props.get("age")); + assertEquals("true", props.get("enabled")); + assertEquals(favoritesString, props.get("favorites")); + assertEquals(nonFavoritesString, props.get("nonFavorites")); + assertNull(props.get("others")); + assertEquals("windows,mac", props.get("systems")); + } + + public void testSetBoolean() { + + TestWitBoolean target = new TestWitBoolean(); + assertTrue(!target.getKeepAlive()); + + IntrospectionSupport.setProperty(target, "keepAlive", "TRUE"); + assertTrue(target.getKeepAlive()); + + IntrospectionSupport.setProperty(target, "keepAlive", "false"); + assertTrue(!target.getKeepAlive()); + } + + public static class TestWitBoolean { + private Boolean keepAlive = new Boolean(false); + public Boolean getKeepAlive() { + return keepAlive; + } + public void setKeepAlive(Boolean keepAlive) { + this.keepAlive = keepAlive; + } + } +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/SimplePojo.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/SimplePojo.java new file mode 100644 index 0000000000..841e2a9c56 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/SimplePojo.java @@ -0,0 +1,84 @@ +/** + * 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.util; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.apache.activemq.command.ActiveMQDestination; + +public class SimplePojo { + + String name; + int age; + boolean enabled; + URI uri; + List favorites = new ArrayList(); + List nonFavorites = new ArrayList(); + List others = new ArrayList(); + String[] systems; + + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public boolean isEnabled() { + return enabled; + } + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public URI getUri() { + return uri; + } + public void setUri(URI uri) { + this.uri = uri; + } + public List getFavorites() { + return favorites; + } + public void setFavorites(List favorites) { + this.favorites = favorites; + } + public List getNonFavorites() { + return nonFavorites; + } + public void setNonFavorites(List nonFavorites) { + this.nonFavorites = nonFavorites; + } + public List getOthers() { + return others; + } + public void setOthers(List others) { + this.others = others; + } + public String[] getSystems() { + return systems; + } + public void setSystems(String[] systems) { + this.systems = systems; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/plugin-broker.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/plugin-broker.xml new file mode 100644 index 0000000000..598ba926b1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/util/plugin-broker.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/ConnectorXBeanConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/ConnectorXBeanConfigTest.java new file mode 100644 index 0000000000..ad96459d73 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/ConnectorXBeanConfigTest.java @@ -0,0 +1,213 @@ +/** + * 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.xbean; + +import java.net.URI; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import javax.jms.*; + +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.broker.TransportConnector; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.MessageIdList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ConnectorXBeanConfigTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(ConnectorXBeanConfigTest.class); + protected BrokerService brokerService; + + public void testConnectorConfiguredCorrectly() throws Exception { + + TransportConnector connector = brokerService.getTransportConnectors().get(0); + + assertEquals(new URI("tcp://localhost:61636"), connector.getUri()); + assertTrue(connector.getTaskRunnerFactory() == brokerService.getTaskRunnerFactory()); + + NetworkConnector netConnector = brokerService.getNetworkConnectors().get(0); + List excludedDestinations = netConnector.getExcludedDestinations(); + assertEquals(new ActiveMQQueue("exclude.test.foo"), excludedDestinations.get(0)); + assertEquals(new ActiveMQTopic("exclude.test.bar"), excludedDestinations.get(1)); + + List dynamicallyIncludedDestinations = netConnector.getDynamicallyIncludedDestinations(); + assertEquals(new ActiveMQQueue("include.test.foo"), dynamicallyIncludedDestinations.get(0)); + assertEquals(new ActiveMQTopic("include.test.bar"), dynamicallyIncludedDestinations.get(1)); + } + + public void testBrokerRestartIsAllowed() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + + // redundant start is now ignored + brokerService.start(); + } + + public void testForceBrokerRestart() throws Exception { + brokerService.stop(); + brokerService.waitUntilStopped(); + + brokerService.start(true); // force restart + brokerService.waitUntilStarted(); + + LOG.info("try and connect to restarted broker"); + //send and receive a message from a restarted broker + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61636"); + Connection conn = factory.createConnection(); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Destination dest = new ActiveMQQueue("test"); + MessageConsumer consumer = sess.createConsumer(dest); + MessageProducer producer = sess.createProducer(dest); + producer.send(sess.createTextMessage("test")); + TextMessage msg = (TextMessage)consumer.receive(1000); + assertEquals("test", msg.getText()); + } + + + public void testBrokerWontStop() throws Exception { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?async=false"); + factory.setDispatchAsync(false); + factory.setAlwaysSessionAsync(false); + Connection conn = factory.createConnection(); + final Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + conn.start(); + final Destination dest = new ActiveMQQueue("TEST"); + final CountDownLatch stop = new CountDownLatch(1); + final CountDownLatch sendSecond = new CountDownLatch(1); + final CountDownLatch shutdown = new CountDownLatch(1); + final CountDownLatch test = new CountDownLatch(1); + + ActiveMQConnectionFactory testFactory = new ActiveMQConnectionFactory("vm://localhost?async=false"); + Connection testConn = testFactory.createConnection(); + testConn.start(); + Destination testDestination = sess.createQueue("NEW"); + Session testSess = testConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer testProducer = testSess.createProducer(testDestination); + + final Thread consumerThread = new Thread() { + @Override + public void run() { + try { + MessageProducer producer = sess.createProducer(dest); + producer.send(sess.createTextMessage("msg1")); + MessageConsumer consumer = sess.createConsumer(dest); + consumer.setMessageListener(new MessageListener() { + @Override + public void onMessage(Message message) { + try { + // send a message that will block + Thread.sleep(2000); + sendSecond.countDown(); + // try to stop the broker + Thread.sleep(5000); + stop.countDown(); + // run the test + Thread.sleep(5000); + test.countDown(); + shutdown.await(); + } catch (InterruptedException ie) { + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + consumerThread.start(); + + final Thread producerThread = new Thread() { + @Override + public void run() { + try { + sendSecond.await(); + MessageProducer producer = sess.createProducer(dest); + producer.send(sess.createTextMessage("msg2")); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + producerThread.start(); + + final Thread stopThread = new Thread() { + @Override + public void run() { + try { + stop.await(); + brokerService.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + stopThread.start(); + + test.await(); + try { + testSess.createConsumer(testDestination); + fail("Should have failed creating a consumer!"); + } catch (Exception e) { + e.printStackTrace(); + } + + try { + testProducer.send(testSess.createTextMessage("msg3")); + fail("Should have failed sending a message!"); + } catch (Exception e) { + e.printStackTrace(); + } + + shutdown.countDown(); + + + } + + @Override + protected void setUp() throws Exception { + brokerService = createBroker(); + brokerService.start(); + } + + @Override + protected void tearDown() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + String uri = "org/apache/activemq/xbean/connector-test.xml"; + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/JDBCPersistenceAdapterXBeanConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/JDBCPersistenceAdapterXBeanConfigTest.java new file mode 100644 index 0000000000..100f244993 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/JDBCPersistenceAdapterXBeanConfigTest.java @@ -0,0 +1,60 @@ +/** + * 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.xbean; + +import java.net.URI; +import junit.framework.TestCase; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; + +/** + * + */ +public class JDBCPersistenceAdapterXBeanConfigTest extends TestCase { + + protected BrokerService brokerService; + + public void testConfiguredCorrectly() throws Exception { + + PersistenceAdapter persistenceAdapter = brokerService.getPersistenceAdapter(); + assertNotNull(persistenceAdapter); + assertTrue(persistenceAdapter instanceof JDBCPersistenceAdapter); + + JDBCPersistenceAdapter jpa = (JDBCPersistenceAdapter)persistenceAdapter; + assertEquals("BROKER1.", jpa.getStatements().getTablePrefix()); + + } + + protected void setUp() throws Exception { + brokerService = createBroker(); + brokerService.start(); + } + + protected void tearDown() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + String uri = "org/apache/activemq/xbean/jdbc-persistence-adapter-test.xml"; + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/JDBCPersistenceXBeanConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/JDBCPersistenceXBeanConfigTest.java new file mode 100644 index 0000000000..5a34932e12 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/JDBCPersistenceXBeanConfigTest.java @@ -0,0 +1,62 @@ +/** + * 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.xbean; + +import java.net.URI; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.store.PersistenceAdapter; +import org.apache.activemq.store.jdbc.JDBCPersistenceAdapter; + +/** + * + */ +public class JDBCPersistenceXBeanConfigTest extends TestCase { + + protected BrokerService brokerService; + + public void testConfiguredCorrectly() throws Exception { + + PersistenceAdapter persistenceAdapter = brokerService.getPersistenceAdapter(); + assertNotNull(persistenceAdapter); + assertTrue(persistenceAdapter instanceof JDBCPersistenceAdapter); + + JDBCPersistenceAdapter jpa = (JDBCPersistenceAdapter)persistenceAdapter; + assertEquals("BROKER1.", jpa.getStatements().getTablePrefix()); + + } + + protected void setUp() throws Exception { + brokerService = createBroker(); + brokerService.start(); + } + + protected void tearDown() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + String uri = "org/apache/activemq/xbean/jdbc-persistence-test.xml"; + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/ManagementContextXBeanConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/ManagementContextXBeanConfigTest.java new file mode 100644 index 0000000000..19361121fe --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/ManagementContextXBeanConfigTest.java @@ -0,0 +1,106 @@ +/** + * 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.xbean; + +import java.net.URI; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.jmx.BrokerViewMBean; +import org.apache.activemq.util.JMXSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class ManagementContextXBeanConfigTest extends TestCase { + + protected BrokerService brokerService; + private static final transient Logger LOG = LoggerFactory.getLogger(ManagementContextXBeanConfigTest.class); + + public void testManagmentContextConfiguredCorrectly() throws Exception { + assertEquals(2011, brokerService.getManagementContext().getConnectorPort()); + assertEquals("test.domain", brokerService.getManagementContext().getJmxDomainName()); + // Make sure the broker is registered in the right jmx domain. + Hashtable map = new Hashtable(); + map.put("type", "Broker"); + map.put("brokerName", JMXSupport.encodeObjectNamePart("localhost")); + ObjectName on = new ObjectName("test.domain", map); + Object value = brokerService.getManagementContext().getAttribute(on, "TotalEnqueueCount"); + assertNotNull(value); + } + + public void testSuccessAuthentication() throws Exception { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:2011/jmxrmi"); + Map env = new HashMap(); + env.put(JMXConnector.CREDENTIALS, new String[]{"admin", "activemq"}); + JMXConnector connector = JMXConnectorFactory.connect(url, env); + assertAuthentication(connector); + } + + public void testFailAuthentication() throws Exception { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:2011/jmxrmi"); + try { + JMXConnector connector = JMXConnectorFactory.connect(url, null); + assertAuthentication(connector); + } catch (SecurityException e) { + return; + } + fail("Should have thrown an exception"); + } + + public void assertAuthentication(JMXConnector connector) throws Exception { + connector.connect(); + MBeanServerConnection connection = connector.getMBeanServerConnection(); + ObjectName name = new ObjectName("test.domain:type=Broker,brokerName=localhost"); + BrokerViewMBean mbean = MBeanServerInvocationHandler + .newProxyInstance(connection, name, BrokerViewMBean.class, true); + LOG.info("Broker " + mbean.getBrokerId() + " - " + mbean.getBrokerName()); + } + + @Override + protected void setUp() throws Exception { + brokerService = createBroker(); + brokerService.start(); + } + + @Override + protected void tearDown() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + String uri = "org/apache/activemq/xbean/management-context-test.xml"; + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithEmbeddedBrokerAndPersistenceTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithEmbeddedBrokerAndPersistenceTest.java new file mode 100644 index 0000000000..5397dc223e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithEmbeddedBrokerAndPersistenceTest.java @@ -0,0 +1,29 @@ +/** + * 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.xbean; + +/** + * + * + */ +public class MultipleTestsWithEmbeddedBrokerAndPersistenceTest extends MultipleTestsWithEmbeddedBrokerTest { + + protected boolean isPersistent() { + return true; + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithEmbeddedBrokerTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithEmbeddedBrokerTest.java new file mode 100644 index 0000000000..64a2c41a5a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithEmbeddedBrokerTest.java @@ -0,0 +1,57 @@ +/** + * 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.xbean; + +import javax.jms.Connection; + +import org.apache.activemq.EmbeddedBrokerTestSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class MultipleTestsWithEmbeddedBrokerTest extends EmbeddedBrokerTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(MultipleTestsWithEmbeddedBrokerTest.class); + + protected Connection connection; + + public void test1() throws Exception { + } + + public void test2() throws Exception { + } + + @Override + protected void setUp() throws Exception { + LOG.info("### starting up the test case: " + getName()); + + super.setUp(); + connection = connectionFactory.createConnection(); + connection.start(); + LOG.info("### started up the test case: " + getName()); + } + + @Override + protected void tearDown() throws Exception { + connection.close(); + + super.tearDown(); + + LOG.info("### closed down the test case: " + getName()); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithSpringFactoryBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithSpringFactoryBeanTest.java new file mode 100644 index 0000000000..8017abd512 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithSpringFactoryBeanTest.java @@ -0,0 +1,81 @@ +/** + * 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.xbean; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; + +import junit.framework.TestCase; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * + * @author Neil Clayton + * + */ +public class MultipleTestsWithSpringFactoryBeanTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(MultipleTestsWithSpringFactoryBeanTest.class); + + protected AbstractApplicationContext context; + protected BrokerService service; + private Connection connection; + + public void test1() throws Exception { + } + + public void test2() throws Exception { + } + + protected void setUp() throws Exception { + LOG.info("### starting up the test case: " + getName()); + + super.setUp(); + context = new ClassPathXmlApplicationContext("org/apache/activemq/xbean/spring2.xml"); + service = (BrokerService) context.getBean("broker"); + + // already started + service.start(); + + connection = createConnectionFactory().createConnection(); + connection.start(); + LOG.info("### started up the test case: " + getName()); + } + + protected void tearDown() throws Exception { + connection.close(); + + // stopped as part of the context + service.stop(); + context.close(); + super.tearDown(); + + LOG.info("### closed down the test case: " + getName()); + } + + protected ConnectionFactory createConnectionFactory() { + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(); + factory.setBrokerURL("vm://localhost"); + return factory; + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithSpringXBeanFactoryBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithSpringXBeanFactoryBeanTest.java new file mode 100644 index 0000000000..252631488a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithSpringXBeanFactoryBeanTest.java @@ -0,0 +1,44 @@ +/** + * 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.xbean; + +import org.apache.activemq.broker.BrokerService; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * + */ +public class MultipleTestsWithSpringXBeanFactoryBeanTest extends MultipleTestsWithEmbeddedBrokerTest { + + private ClassPathXmlApplicationContext context; + + protected BrokerService createBroker() throws Exception { + context = new ClassPathXmlApplicationContext("org/apache/activemq/xbean/spring2.xml"); + return (BrokerService) context.getBean("broker"); + } + + protected void tearDown() throws Exception { + super.tearDown(); + if (context != null) { + context.destroy(); + } + } + + + +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithXBeanFactoryBeanTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithXBeanFactoryBeanTest.java new file mode 100644 index 0000000000..f6b15072c1 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/MultipleTestsWithXBeanFactoryBeanTest.java @@ -0,0 +1,36 @@ +/** + * 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.xbean; + +import org.apache.activemq.broker.BrokerService; +import org.springframework.core.io.ClassPathResource; + +/** + * + */ +public class MultipleTestsWithXBeanFactoryBeanTest extends MultipleTestsWithEmbeddedBrokerTest { + + protected BrokerService createBroker() throws Exception { + BrokerFactoryBean factory = new BrokerFactoryBean(); + factory.setConfig(new ClassPathResource("org/apache/activemq/xbean/activemq2.xml")); + factory.afterPropertiesSet(); + return factory.getBroker(); + } + + +} + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanConfigTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanConfigTest.java new file mode 100644 index 0000000000..c29a08cc2e --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanConfigTest.java @@ -0,0 +1,121 @@ +/** + * 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.xbean; + +import java.net.URI; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.ConnectionContext; +import org.apache.activemq.broker.region.Topic; +import org.apache.activemq.broker.region.policy.*; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.command.ConnectionId; +import org.apache.activemq.command.ConnectionInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class XBeanConfigTest extends TestCase { + + private static final Logger LOG = LoggerFactory.getLogger(XBeanConfigTest.class); + + protected BrokerService brokerService; + protected Broker broker; + protected ConnectionContext context; + protected ConnectionInfo info; + + public void testBrokerConfiguredCorrectly() throws Exception { + + // Validate the system properties are being evaluated in xbean. + assertEquals("testbroker", brokerService.getBrokerName()); + + Topic topic = (Topic)broker.addDestination(context, new ActiveMQTopic("FOO.BAR"),true); + DispatchPolicy dispatchPolicy = topic.getDispatchPolicy(); + assertTrue("dispatchPolicy should be RoundRobinDispatchPolicy: " + dispatchPolicy, dispatchPolicy instanceof RoundRobinDispatchPolicy); + + SubscriptionRecoveryPolicy subscriptionRecoveryPolicy = topic.getSubscriptionRecoveryPolicy(); + subscriptionRecoveryPolicy = ((RetainedMessageSubscriptionRecoveryPolicy)subscriptionRecoveryPolicy).getWrapped(); + + assertTrue("subscriptionRecoveryPolicy should be LastImageSubscriptionRecoveryPolicy: " + subscriptionRecoveryPolicy, + subscriptionRecoveryPolicy instanceof LastImageSubscriptionRecoveryPolicy); + + LOG.info("destination: " + topic); + LOG.info("dispatchPolicy: " + dispatchPolicy); + LOG.info("subscriptionRecoveryPolicy: " + subscriptionRecoveryPolicy); + + topic = (Topic)broker.addDestination(context, new ActiveMQTopic("ORDERS.BOOKS"),true); + dispatchPolicy = topic.getDispatchPolicy(); + assertTrue("dispatchPolicy should be StrictOrderDispatchPolicy: " + dispatchPolicy, dispatchPolicy instanceof StrictOrderDispatchPolicy); + + subscriptionRecoveryPolicy = topic.getSubscriptionRecoveryPolicy(); + subscriptionRecoveryPolicy = ((RetainedMessageSubscriptionRecoveryPolicy)subscriptionRecoveryPolicy).getWrapped(); + assertTrue("subscriptionRecoveryPolicy should be TimedSubscriptionRecoveryPolicy: " + subscriptionRecoveryPolicy, + subscriptionRecoveryPolicy instanceof TimedSubscriptionRecoveryPolicy); + TimedSubscriptionRecoveryPolicy timedSubscriptionPolicy = (TimedSubscriptionRecoveryPolicy)subscriptionRecoveryPolicy; + assertEquals("getRecoverDuration()", 60000, timedSubscriptionPolicy.getRecoverDuration()); + + LOG.info("destination: " + topic); + LOG.info("dispatchPolicy: " + dispatchPolicy); + LOG.info("subscriptionRecoveryPolicy: " + subscriptionRecoveryPolicy); + } + + @Override + protected void setUp() throws Exception { + System.setProperty("brokername", "testbroker"); + brokerService = createBroker(); + broker = brokerService.getBroker(); + + // started automatically + // brokerService.start(); + + context = new ConnectionContext(); + context.setBroker(broker); + info = new ConnectionInfo(); + info.setClientId("James"); + info.setUserName("James"); + info.setConnectionId(new ConnectionId("1234")); + + try { + broker.addConnection(context, info); + } catch (Throwable e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + assertNotNull("No broker created!"); + } + + @Override + protected void tearDown() throws Exception { + if (brokerService != null) { + brokerService.stop(); + } + } + + protected BrokerService createBroker() throws Exception { + String uri = "org/apache/activemq/xbean/activemq-policy.xml"; + LOG.info("Loading broker configuration from the classpath with URI: " + uri); + return BrokerFactory.createBroker(new URI("xbean:" + uri)); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanStartFalseTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanStartFalseTest.java new file mode 100644 index 0000000000..13f50648b4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanStartFalseTest.java @@ -0,0 +1,33 @@ +/** + * 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.xbean; + +import java.net.URI; + +import junit.framework.TestCase; + +import org.apache.activemq.broker.BrokerFactory; +import org.apache.activemq.broker.BrokerService; + +public class XBeanStartFalseTest extends TestCase { + + public void testStartFalse() throws Exception { + BrokerService broker = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/xbean/activemq2.xml")); + assertFalse("Broker is started", broker.isStarted()); + } + +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanXmlTest.java b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanXmlTest.java new file mode 100644 index 0000000000..3a98114dab --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/XBeanXmlTest.java @@ -0,0 +1,26 @@ +/** + * 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.xbean; + +import org.apache.activemq.broker.SpringTest; + +public class XBeanXmlTest extends SpringTest { + + public void testSenderWithSpringXml() throws Exception { + assertSenderConfig("org/apache/activemq/xbean/spring.xml"); + } +} diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq-policy.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq-policy.xml new file mode 100644 index 0000000000..1188734af4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq-policy.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq.xml new file mode 100644 index 0000000000..9884523485 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq2.xml new file mode 100644 index 0000000000..78d19959f6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/activemq2.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/connector-test.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/connector-test.xml new file mode 100644 index 0000000000..5fb64033d4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/connector-test.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/jdbc-persistence-adapter-test.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/jdbc-persistence-adapter-test.xml new file mode 100644 index 0000000000..e5f4f2624a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/jdbc-persistence-adapter-test.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/jdbc-persistence-test.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/jdbc-persistence-test.xml new file mode 100644 index 0000000000..d00a8b980b --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/jdbc-persistence-test.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/management-context-test.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/management-context-test.xml new file mode 100644 index 0000000000..98f8c0f521 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/management-context-test.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/spring.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/spring.xml new file mode 100644 index 0000000000..ef37855089 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/spring.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/spring2.xml b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/spring2.xml new file mode 100644 index 0000000000..395e24deee --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/org/apache/activemq/xbean/spring2.xml @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/provider.properties b/tests/activemq5-unit-tests/src/test/java/provider.properties new file mode 100644 index 0000000000..d140d028cf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/provider.properties @@ -0,0 +1,20 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# This config file is used by the joram jms tests. +# +jms.provider.admin.class=org.apache.activemq.joramtests.ActiveMQAdmin \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/server.keystore b/tests/activemq5-unit-tests/src/test/java/server.keystore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-bean-ref.xml b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-bean-ref.xml new file mode 100644 index 0000000000..b6daf725c6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-bean-ref.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-local.xml b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-local.xml new file mode 100644 index 0000000000..584faea2b6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-local.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-noversion.xml b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-noversion.xml new file mode 100644 index 0000000000..e21073c3a3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean-noversion.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean.xml b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean.xml new file mode 100644 index 0000000000..e21073c3a3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-embedded-xbean.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/spring-embedded.xml b/tests/activemq5-unit-tests/src/test/java/spring-embedded.xml new file mode 100644 index 0000000000..39f09503ea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-embedded.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + org.apache.activemq.spring.Test.spring.embedded + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/spring-jndi.xml b/tests/activemq5-unit-tests/src/test/java/spring-jndi.xml new file mode 100644 index 0000000000..4ad519b1d8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-jndi.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + org.apache.activemq.jndi.ActiveMQInitialContextFactory + + example.Spring.MyTopic + + + + + + + + + + + ConnectionFactory + + + + + + + + + + MyTopic + + + + + + true + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + example.Spring.MyTopic + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/spring-queue.xml b/tests/activemq5-unit-tests/src/test/java/spring-queue.xml new file mode 100644 index 0000000000..94c31a2a5c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-queue.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + false + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + + org.apache.activemq.spring.Test.spring.queue + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/spring-start-false.xml b/tests/activemq5-unit-tests/src/test/java/spring-start-false.xml new file mode 100644 index 0000000000..447921e40f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring-start-false.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/java/spring.xml b/tests/activemq5-unit-tests/src/test/java/spring.xml new file mode 100644 index 0000000000..51eb08d03a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/spring.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + org.apache.activemq.spring.Test.spring.topic + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/java/test.properties b/tests/activemq5-unit-tests/src/test/java/test.properties new file mode 100644 index 0000000000..5820670e97 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/java/test.properties @@ -0,0 +1,20 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# This config file is used by the joram jms tests. +# +timeout=30000 \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/resources/activemq-browse.properties b/tests/activemq5-unit-tests/src/test/resources/activemq-browse.properties new file mode 100644 index 0000000000..36559c7877 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/activemq-browse.properties @@ -0,0 +1,61 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# Remote addresses for the other brokers in mesh + + +# 1a +1a.name=1a-nc +1a.uri=failover:(tcp://localhost:6106)?randomize=false +1a.transport=tcp://localhost:6106 +1a.jmx=1090 +1a.data=target/data/1a_store + +# 1b +1b.name=1b-nc +1b.uri=failover:(tcp://localhost:6107)?randomize=false +1b.transport=tcp://localhost:6107 +1b.jmx=1091 +1b.data=target/data/1b_store + +# 2a +2a.name=2a-nc +2a.uri=failover:(tcp://localhost:6108)?randomize=false +2a.transport=tcp://localhost:6108 +2a.jmx=1092 +2a.data=target/data/2a_store + +# 2b +2b.name=2b-nc +2b.uri=failover:(tcp://localhost:6109)?randomize=false +2b.transport=tcp://localhost:6109 +2b.jmx=1093 +2b.data=target/data/2b_store + +# 3a +3a.name=3a-nc +3a.uri=failover:(tcp://localhost:6110)?randomize=false +3a.transport=tcp://localhost:6110 +3a.jmx=1094 +3a.data=target/data/3a_store + +# 3b +3b.name=3b-nc +3b.uri=failover:(tcp://localhost:6111)?randomize=false +3b.transport=tcp://localhost:6111 +3b.jmx=1095 +3b.data=target/data/3b_store diff --git a/tests/activemq5-unit-tests/src/test/resources/activemq-partition.xml b/tests/activemq5-unit-tests/src/test/resources/activemq-partition.xml new file mode 100644 index 0000000000..4bb96f22a9 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/activemq-partition.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/activemq.xml b/tests/activemq5-unit-tests/src/test/resources/activemq.xml new file mode 100644 index 0000000000..eb49ca08d0 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/activemq.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/client.keystore b/tests/activemq5-unit-tests/src/test/resources/client.keystore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/resources/credentials.properties b/tests/activemq5-unit-tests/src/test/resources/credentials.properties new file mode 100644 index 0000000000..86f719940f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/credentials.properties @@ -0,0 +1,24 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# Defines credentials that will be used by components (like web console) to access the broker + +activemq.username=system +#activemq.password=manager +activemq.password=ENC(mYRkg+4Q4hua1kvpCCI2hg==) +#guest.password=password +guest.password=ENC(Cf3Jf3tM+UrSOoaKU50od5CuBa8rxjoL) \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/resources/dummy.keystore b/tests/activemq5-unit-tests/src/test/resources/dummy.keystore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/resources/jmx.access b/tests/activemq5-unit-tests/src/test/resources/jmx.access new file mode 100644 index 0000000000..4625b7dea4 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/jmx.access @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +admin readwrite \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/resources/jmx.password b/tests/activemq5-unit-tests/src/test/resources/jmx.password new file mode 100644 index 0000000000..053aa659f8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/jmx.password @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +admin activemq \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/resources/jndi.properties b/tests/activemq5-unit-tests/src/test/resources/jndi.properties new file mode 100644 index 0000000000..d627de9c34 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/jndi.properties @@ -0,0 +1,38 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# START SNIPPET: jndi + +java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory + +# use the following property to configure the default connector +java.naming.provider.url = vm://localhost + +# use the following property to specify the JNDI name the connection factory +# should appear as. +#connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry + +# register some queues in JNDI using the form +# queue.[jndiName] = [physicalName] +queue.MyQueue = example.MyQueue + + +# register some topics in JNDI using the form +# topic.[jndiName] = [physicalName] +topic.MyTopic = example.MyTopic + +# END SNIPPET: jndi diff --git a/tests/activemq5-unit-tests/src/test/resources/log4j.properties b/tests/activemq5-unit-tests/src/test/resources/log4j.properties new file mode 100644 index 0000000000..4704dbc325 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/log4j.properties @@ -0,0 +1,46 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# +# The logging properties used during tests.. +# +log4j.rootLogger=INFO, out, stdout + +#log4j.logger.org.apache.activemq.broker.scheduler=DEBUG +#log4j.logger.org.apache.activemq.store.kahadb.scheduler=DEBUG +#log4j.logger.org.apache.activemq.network.DemandForwardingBridgeSupport=DEBUG +#log4j.logger.org.apache.activemq.transport.failover=TRACE +#log4j.logger.org.apache.activemq.store.jdbc=TRACE +#log4j.logger.org.apache.activemq.store.kahadb=TRACE +#log4j.logger.org.apache.activemq.broker.region.cursors.AbstractStoreCursor=DEBUG +#log4j.logger.org.apache.activemq.store.jdbc.JDBCMessageStore=DEBUG +#log4j.logger.org.apache.activemq.store.kahadb.disk.journal=DEBUG +#log4j.logger.org.apache.activemq.store.kahadb.AbstractKahaDBStore=DEBUG + +# CONSOLE appender not used by default +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n +#log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %-10.10X{activemq.broker} %-20.20X{activemq.connector} %-10.10X{activemq.destination} - %m%n + +# File appender +log4j.appender.out=org.apache.log4j.FileAppender +log4j.appender.out.layout=org.apache.log4j.PatternLayout +log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n +#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %-10.10X{activemq.broker} %-20.20X{activemq.connector} %-10.10X{activemq.destination} - %m%n +log4j.appender.out.file=target/activemq-test.log +log4j.appender.out.append=true diff --git a/tests/activemq5-unit-tests/src/test/resources/login.config b/tests/activemq5-unit-tests/src/test/resources/login.config new file mode 100644 index 0000000000..1f5f77c805 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/login.config @@ -0,0 +1,87 @@ +/** + * 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. + */ +activemq-domain { + org.apache.activemq.jaas.PropertiesLoginModule required + debug=true + org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties"; +}; + +activemq-guest-domain { + org.apache.activemq.jaas.PropertiesLoginModule sufficient + debug=true + org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties"; + org.apache.activemq.jaas.GuestLoginModule sufficient + debug=true + org.apache.activemq.jaas.guest.user="guest" + org.apache.activemq.jaas.guest.group="guests"; +}; + +activemq-guest-when-no-creds-only-domain { + org.apache.activemq.jaas.GuestLoginModule sufficient + debug=true + credentialsInvalidate=true + org.apache.activemq.jaas.guest.user="guest" + org.apache.activemq.jaas.guest.group="guests"; + + org.apache.activemq.jaas.PropertiesLoginModule requisite + debug=true + org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties"; +}; + +cert-login { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users.properties" + org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; + +}; + +broker1 { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users1.properties" + org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; +}; + +broker2 { + org.apache.activemq.jaas.TextFileCertificateLoginModule required + debug=true + org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users2.properties" + org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties"; +}; + +LDAPLogin { + org.apache.activemq.jaas.LDAPLoginModule required + debug=true + initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory + connectionURL="ldap://localhost:1024" + connectionUsername="uid=admin,ou=system" + connectionPassword=secret + connectionProtocol=s + authentication=simple + userBase="ou=User,ou=ActiveMQ,ou=system" + userSearchMatching="(uid={0})" + userSearchSubtree=false + roleBase="ou=Group,ou=ActiveMQ,ou=system" + roleName=cn + roleSearchMatching="(uid={1})" + roleSearchSubtree=true + ; +}; \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/resources/provider.properties b/tests/activemq5-unit-tests/src/test/resources/provider.properties new file mode 100644 index 0000000000..d140d028cf --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/provider.properties @@ -0,0 +1,20 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# This config file is used by the joram jms tests. +# +jms.provider.admin.class=org.apache.activemq.joramtests.ActiveMQAdmin \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/resources/server.keystore b/tests/activemq5-unit-tests/src/test/resources/server.keystore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-bean-ref.xml b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-bean-ref.xml new file mode 100644 index 0000000000..b6daf725c6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-bean-ref.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-local.xml b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-local.xml new file mode 100644 index 0000000000..584faea2b6 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-local.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-noversion.xml b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-noversion.xml new file mode 100644 index 0000000000..e21073c3a3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean-noversion.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean.xml b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean.xml new file mode 100644 index 0000000000..e21073c3a3 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-embedded-xbean.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-embedded.xml b/tests/activemq5-unit-tests/src/test/resources/spring-embedded.xml new file mode 100644 index 0000000000..39f09503ea --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-embedded.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + org.apache.activemq.spring.Test.spring.embedded + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-jndi.xml b/tests/activemq5-unit-tests/src/test/resources/spring-jndi.xml new file mode 100644 index 0000000000..4ad519b1d8 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-jndi.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + org.apache.activemq.jndi.ActiveMQInitialContextFactory + + example.Spring.MyTopic + + + + + + + + + + + ConnectionFactory + + + + + + + + + + MyTopic + + + + + + true + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + example.Spring.MyTopic + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-queue.xml b/tests/activemq5-unit-tests/src/test/resources/spring-queue.xml new file mode 100644 index 0000000000..94c31a2a5c --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-queue.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + false + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + + org.apache.activemq.spring.Test.spring.queue + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/spring-start-false.xml b/tests/activemq5-unit-tests/src/test/resources/spring-start-false.xml new file mode 100644 index 0000000000..447921e40f --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring-start-false.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/activemq5-unit-tests/src/test/resources/spring.xml b/tests/activemq5-unit-tests/src/test/resources/spring.xml new file mode 100644 index 0000000000..51eb08d03a --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/spring.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + org.apache.activemq.spring.Test.spring.topic + + + + + + diff --git a/tests/activemq5-unit-tests/src/test/resources/test.properties b/tests/activemq5-unit-tests/src/test/resources/test.properties new file mode 100644 index 0000000000..5820670e97 --- /dev/null +++ b/tests/activemq5-unit-tests/src/test/resources/test.properties @@ -0,0 +1,20 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# This config file is used by the joram jms tests. +# +timeout=30000 \ No newline at end of file diff --git a/tests/pom.xml b/tests/pom.xml index b3888244ef..503334de0a 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -84,6 +84,15 @@ false + + activemq5-unit-tests + + activemq5-unit-tests + + + false + +