ARTEMIS-3969 Removing Extra tests from the codebase
This commit is contained in:
parent
90966ccdf1
commit
f953408185
|
@ -71,7 +71,7 @@ jobs:
|
|||
|
||||
- name: Build Main
|
||||
run: |
|
||||
mvn -s .github/maven-settings.xml -DskipTests -Derrorprone -Pdev -Pextra-tests -Pjmh install
|
||||
mvn -s .github/maven-settings.xml -DskipTests -Derrorprone -Pdev -Pjmh install
|
||||
|
||||
- name: Build Examples (JDK11 / -Prelease)
|
||||
if: matrix.java == '11'
|
||||
|
|
|
@ -16,11 +16,10 @@ before_install:
|
|||
- rm -rf $HOME/.m2/repository/org/apache/activemq/artemis-*
|
||||
|
||||
# use 'install' so smoke-tests will work
|
||||
# use '-Pextra-tests' to ensure extra-tests compiles even though they won't actually run
|
||||
# By setting anything to org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory.DISABLED we are disabling libaio loading on the testsuite
|
||||
script:
|
||||
- set -e
|
||||
- mvn -s .github/maven-settings.xml -ntp -Dorg.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory.DISABLED=AnythingNotNull -Dmaven.test.redirectTestOutputToFile=true -Derrorprone -Pdev -Pfast-tests -Pextra-tests -Ptests-CI -Pjmh -B install
|
||||
- mvn -s .github/maven-settings.xml -ntp -Dorg.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory.DISABLED=AnythingNotNull -Dmaven.test.redirectTestOutputToFile=true -Derrorprone -Pdev -Pfast-tests -Ptests-CI -Pjmh -B install
|
||||
- cd examples
|
||||
- mvn -s ../.github/maven-settings.xml verify -P${EXAMPLES_PROFILE} -B -q
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ agent and stored in JaCoCo exec files. All you need to do
|
|||
is run the tests with `jacoco` maven profile.
|
||||
|
||||
```
|
||||
mvn test -Ptests,extra-tests,jacoco
|
||||
mvn test -Ptests,jacoco
|
||||
```
|
||||
|
||||
## Generate JaCoCo reports
|
||||
|
|
|
@ -11,7 +11,7 @@ What does it mean to be reasonably confident? If the developer has run the same
|
|||
builds are running they can be reasonably confident. Currently the [PR build](https://builds.apache.org/job/ActiveMQ-Artemis-PR-Build/)
|
||||
runs this command:
|
||||
|
||||
mvn -Pfast-tests -Pextra-tests install
|
||||
mvn -Pfast-tests install
|
||||
|
||||
However, if the changes are significant, touches a wide area of code, or even if the developer just wants a second
|
||||
opinion they are encouraged to engage other members of the community to obtain an additional review prior to pushing.
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
mvn -Ptests,jacoco -DfailIfNoTests=false -Pextra-tests -DskipStyleCheck=true -DskipPerformanceTests=false -Dtest=$1 test
|
||||
mvn -Ptests,jacoco -DfailIfNoTests=false -DskipStyleCheck=true -DskipPerformanceTests=false -Dtest=$1 test
|
||||
mvn jacoco:merge -N -Pjacoco
|
||||
mvn verify -Pjacoco-generate-report -DskipTests
|
||||
|
|
|
@ -16,4 +16,4 @@
|
|||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
mvn -Ptests -DfailIfNoTests=false -Ptests-retry -Pextra-tests -DskipStyleCheck=true -DskipPerformanceTests=false -DskipSoakTests=false -Dtest=$1 test
|
||||
mvn -Ptests -DfailIfNoTests=false -Ptests-retry -DskipStyleCheck=true -DskipPerformanceTests=false -DskipSoakTests=false -Dtest=$1 test
|
||||
|
|
|
@ -1,291 +0,0 @@
|
|||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT 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 test folder contains tests that are not part of the regular testsuite
|
||||
because they use optional libraries such as LGPL or private ones.
|
||||
They are optional and will validate extra functionality available through Service Integration
|
||||
Example: Transaction Manager -->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.activemq.tests</groupId>
|
||||
<artifactId>artemis-tests-pom</artifactId>
|
||||
<version>2.26.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>extra-tests</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>ActiveMQ Artemis Extra Tests</name>
|
||||
|
||||
<properties>
|
||||
<activemq.basedir>${project.basedir}/../..</activemq.basedir>
|
||||
<jboss-jts.version>4.17.13.Final</jboss-jts.version>
|
||||
<hornetq.version>2.4.7.Final</hornetq.version>
|
||||
<openhft.core.version>1.4.9</openhft.core.version>
|
||||
<openhft.affinity.version>3.0.6</openhft.affinity.version>
|
||||
<openjdk.jmh.version>1.12</openjdk.jmh.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.byteman</groupId>
|
||||
<artifactId>byteman</artifactId>
|
||||
<version>${byteman.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.byteman</groupId>
|
||||
<artifactId>byteman-submit</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${byteman.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.byteman</groupId>
|
||||
<artifactId>byteman-install</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${byteman.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-junit</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.byteman</groupId>
|
||||
<artifactId>byteman-bmunit</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${byteman.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-core-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.tests</groupId>
|
||||
<artifactId>integration-tests</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.tests</groupId>
|
||||
<artifactId>unit-tests</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-jms-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-jms-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-ra</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-hqclient-protocol</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-service-extensions</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.resource</groupId>
|
||||
<artifactId>jakarta.resource-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.transaction</groupId>
|
||||
<artifactId>jakarta.transaction-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.jms</groupId>
|
||||
<artifactId>jakarta.jms-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging-processor</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logmanager</groupId>
|
||||
<artifactId>jboss-logmanager</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wildfly.common</groupId>
|
||||
<artifactId>wildfly-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-unit-test-support</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq.tests</groupId>
|
||||
<artifactId>artemis-test-support</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- this is for the log assertion -->
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-commons</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-hornetq-protocol</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Needed for JMS Bridge Tests -->
|
||||
<dependency>
|
||||
<groupId>org.jboss</groupId>
|
||||
<artifactId>jboss-transaction-spi</artifactId>
|
||||
<version>7.1.0.Final</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.hornetq</groupId>
|
||||
<artifactId>hornetq-commons</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hornetq</groupId>
|
||||
<artifactId>hornetq-core-client</artifactId>
|
||||
<version>${hornetq.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Needed for XA tests -->
|
||||
<dependency>
|
||||
<groupId>org.jboss.jbossts.jts</groupId>
|
||||
<artifactId>jbossjts-jacorb</artifactId>
|
||||
<version>4.17.13.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>${skipExtraTests}</skipTests>
|
||||
<!-- ensure we don't inherit a byteman jar form any env settings -->
|
||||
<environmentVariables>
|
||||
<BYTEMAN_HOME />
|
||||
</environmentVariables>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>com.arjuna.ats.arjuna.objectstore.objectStoreDir</name>
|
||||
<value>target/ObjectStore</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>ObjectStoreEnvironmentBean.objectStoreDir</name>
|
||||
<value>target/ObjectStore</value>
|
||||
</property>
|
||||
<!--
|
||||
<property>
|
||||
<name>org.jboss.byteman.home</name>
|
||||
<value></value>
|
||||
</property>
|
||||
<property>
|
||||
<name>org.jboss.byteman.verbose</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>org.jboss.byteman.contrib.bmunit.verbose</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>org.jboss.byteman.dump.generated.classes</name>
|
||||
<value></value>
|
||||
</property>
|
||||
-->
|
||||
</systemProperties>
|
||||
<!-- make sure maven puts the byteman jar in the classpath rather than in a manifest jar -->
|
||||
<useManifestOnlyJar>false</useManifestOnlyJar>
|
||||
<!-- when upgrading this plugin from 2.4 to 2.18.1 <forkMode>once</forkMode> was replaced with these: -->
|
||||
<forkCount>1</forkCount>
|
||||
<reuseForks>true</reuseForks>
|
||||
<!--
|
||||
<debugForkedProcess>true</debugForkedProcess>
|
||||
-->
|
||||
|
||||
<!-- the option <parallel>false</parallel> is not supported after the plugin upgrade from 2.4 to 2.18.1 -->
|
||||
|
||||
<!--<argLine>${activemq-surefire-argline} -Dorg.jboss.byteman.verbose -Dorg.jboss.byteman.contrib.bmunit.verbose</argLine>-->
|
||||
<!-- '-noverify' is needed here to fix VerifyErrors on ScaleDownFailoverTest and ScaleDownFailureTest (and their subclasses). I got the tip from https://issues.jboss.org/browse/BYTEMAN-248. -->
|
||||
<argLine>${activemq-surefire-argline} -noverify</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Don't deploy artifacts for this module. It has non-permissive
|
||||
dependencies and is only optionally used for local testing. -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras;
|
||||
|
||||
import org.jboss.logging.BasicLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.annotations.MessageLogger;
|
||||
|
||||
@MessageLogger(projectCode = "AMQTEST")
|
||||
public interface ExtrasTestLogger extends BasicLogger {
|
||||
|
||||
/**
|
||||
* The integration test logger.
|
||||
*/
|
||||
ExtrasTestLogger LOGGER = Logger.getMessageLogger(ExtrasTestLogger.class, ExtrasTestLogger.class.getPackage().getName());
|
||||
}
|
|
@ -1,375 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Message;
|
||||
import javax.resource.ResourceException;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAException;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import javax.transaction.xa.Xid;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.arjuna.ats.arjuna.coordinator.TransactionReaper;
|
||||
import com.arjuna.ats.arjuna.coordinator.TxControl;
|
||||
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.core.postoffice.Binding;
|
||||
import org.apache.activemq.artemis.core.server.Queue;
|
||||
import org.apache.activemq.artemis.ra.ActiveMQResourceAdapter;
|
||||
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivationSpec;
|
||||
import org.apache.activemq.artemis.tests.integration.ra.ActiveMQRATestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ActiveMQMessageHandlerTest extends ActiveMQRATestBase {
|
||||
|
||||
@Override
|
||||
protected boolean usePersistence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSecurity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "interrupt",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext",
|
||||
targetMethod = "xaEnd",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ActiveMQMessageHandlerTest.interrupt();")})
|
||||
public void testSimpleMessageReceivedOnQueue() throws Exception {
|
||||
ActiveMQResourceAdapter qResourceAdapter = newResourceAdapter();
|
||||
resourceAdapter = qResourceAdapter;
|
||||
|
||||
MyBootstrapContext ctx = new MyBootstrapContext();
|
||||
|
||||
qResourceAdapter.setConnectorClassName(NETTY_CONNECTOR_FACTORY);
|
||||
qResourceAdapter.start(ctx);
|
||||
|
||||
ActiveMQActivationSpec spec = new ActiveMQActivationSpec();
|
||||
spec.setMaxSession(1);
|
||||
spec.setCallTimeout(1000L);
|
||||
spec.setResourceAdapter(qResourceAdapter);
|
||||
spec.setUseJNDI(false);
|
||||
spec.setDestinationType("javax.jms.Queue");
|
||||
spec.setDestination(MDBQUEUE);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
XADummyEndpoint endpoint = new XADummyEndpoint(latch, false);
|
||||
|
||||
DummyMessageEndpointFactory endpointFactory = new DummyMessageEndpointFactory(endpoint, true);
|
||||
|
||||
qResourceAdapter.endpointActivation(endpointFactory, spec);
|
||||
|
||||
ClientSession session = locator.createSessionFactory().createSession();
|
||||
|
||||
ClientProducer clientProducer = session.createProducer(MDBQUEUEPREFIXED);
|
||||
|
||||
ClientMessage message = session.createMessage(true);
|
||||
|
||||
message.getBodyBuffer().writeString("teststring");
|
||||
|
||||
clientProducer.send(message);
|
||||
|
||||
session.close();
|
||||
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
assertNotNull(endpoint.lastMessage);
|
||||
assertEquals(endpoint.lastMessage.getCoreMessage().getBodyBuffer().readString(), "teststring");
|
||||
|
||||
qResourceAdapter.endpointDeactivation(endpointFactory, spec);
|
||||
|
||||
qResourceAdapter.stop();
|
||||
|
||||
Binding binding = server.getPostOffice().getBinding(SimpleString.toSimpleString(MDBQUEUEPREFIXED));
|
||||
assertEquals(1, getMessageCount(((Queue) binding.getBindable())));
|
||||
|
||||
server.stop();
|
||||
server.start();
|
||||
|
||||
ClientSessionFactory factory = locator.createSessionFactory();
|
||||
session = factory.createSession(true, true);
|
||||
|
||||
session.start();
|
||||
ClientConsumer consumer = session.createConsumer(MDBQUEUEPREFIXED);
|
||||
assertNotNull(consumer.receive(5000));
|
||||
session.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "interrupt",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext",
|
||||
targetMethod = "xaEnd",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ActiveMQMessageHandlerTest.interrupt();")})
|
||||
public void testSimpleMessageReceivedOnQueueTwoPhase() throws Exception {
|
||||
ActiveMQResourceAdapter qResourceAdapter = newResourceAdapter();
|
||||
resourceAdapter = qResourceAdapter;
|
||||
|
||||
MyBootstrapContext ctx = new MyBootstrapContext();
|
||||
|
||||
qResourceAdapter.setConnectorClassName(NETTY_CONNECTOR_FACTORY);
|
||||
qResourceAdapter.start(ctx);
|
||||
|
||||
ActiveMQActivationSpec spec = new ActiveMQActivationSpec();
|
||||
spec.setMaxSession(1);
|
||||
spec.setCallTimeout(1000L);
|
||||
spec.setResourceAdapter(qResourceAdapter);
|
||||
spec.setUseJNDI(false);
|
||||
spec.setDestinationType("javax.jms.Queue");
|
||||
spec.setDestination(MDBQUEUE);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
XADummyEndpoint endpoint = new XADummyEndpoint(latch, true);
|
||||
|
||||
DummyMessageEndpointFactory endpointFactory = new DummyMessageEndpointFactory(endpoint, true);
|
||||
|
||||
qResourceAdapter.endpointActivation(endpointFactory, spec);
|
||||
|
||||
ClientSession session = locator.createSessionFactory().createSession();
|
||||
|
||||
ClientProducer clientProducer = session.createProducer(MDBQUEUEPREFIXED);
|
||||
|
||||
ClientMessage message = session.createMessage(true);
|
||||
|
||||
message.getBodyBuffer().writeString("teststring");
|
||||
|
||||
clientProducer.send(message);
|
||||
|
||||
session.close();
|
||||
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
assertNotNull(endpoint.lastMessage);
|
||||
assertEquals(endpoint.lastMessage.getCoreMessage().getBodyBuffer().readString(), "teststring");
|
||||
|
||||
qResourceAdapter.endpointDeactivation(endpointFactory, spec);
|
||||
|
||||
qResourceAdapter.stop();
|
||||
|
||||
Binding binding = server.getPostOffice().getBinding(SimpleString.toSimpleString(MDBQUEUEPREFIXED));
|
||||
assertEquals(1, getMessageCount(((Queue) binding.getBindable())));
|
||||
|
||||
server.stop();
|
||||
server.start();
|
||||
|
||||
ClientSessionFactory factory = locator.createSessionFactory();
|
||||
session = factory.createSession(true, true);
|
||||
|
||||
session.start();
|
||||
ClientConsumer consumer = session.createConsumer(MDBQUEUEPREFIXED);
|
||||
assertNotNull(consumer.receive(5000));
|
||||
session.close();
|
||||
}
|
||||
|
||||
static volatile ActiveMQResourceAdapter resourceAdapter;
|
||||
static boolean resourceAdapterStopped = false;
|
||||
|
||||
public static void interrupt() throws InterruptedException {
|
||||
//Thread.currentThread().interrupt();
|
||||
if (!resourceAdapterStopped) {
|
||||
resourceAdapter.stop();
|
||||
resourceAdapterStopped = true;
|
||||
throw new InterruptedException("foo");
|
||||
}
|
||||
//Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
Transaction currentTX;
|
||||
|
||||
public class XADummyEndpoint extends DummyMessageEndpoint {
|
||||
|
||||
final boolean twoPhase;
|
||||
ClientSession session;
|
||||
int afterDeliveryCounts = 0;
|
||||
|
||||
public XADummyEndpoint(CountDownLatch latch, boolean twoPhase) throws SystemException {
|
||||
super(latch);
|
||||
this.twoPhase = twoPhase;
|
||||
try {
|
||||
session = locator.createSessionFactory().createSession(true, false, false);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDelivery(Method method) throws NoSuchMethodException, ResourceException {
|
||||
super.beforeDelivery(method);
|
||||
try {
|
||||
DummyTMLocator.tm.begin();
|
||||
currentTX = DummyTMLocator.tm.getTransaction();
|
||||
currentTX.enlistResource(xaResource);
|
||||
if (twoPhase) {
|
||||
currentTX.enlistResource(new DummyXAResource());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message) {
|
||||
super.onMessage(message);
|
||||
// try
|
||||
// {
|
||||
// lastMessage = (ActiveMQMessage) message;
|
||||
// currentTX.enlistResource(session);
|
||||
// ClientProducer prod = session.createProducer()
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDelivery() throws ResourceException {
|
||||
afterDeliveryCounts++;
|
||||
try {
|
||||
currentTX.commit();
|
||||
} catch (Throwable e) {
|
||||
//its unsure as to whether the EJB/JCA layer will handle this or throw it to us,
|
||||
// either way we don't do anything else so its fine just to throw.
|
||||
// NB this will only happen with 2 phase commit
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
super.afterDelivery();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
resourceAdapter = null;
|
||||
resourceAdapterStopped = false;
|
||||
super.setUp();
|
||||
DummyTMLocator.startTM();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
DummyTMLocator.stopTM();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public static class DummyTMLocator {
|
||||
|
||||
public static TransactionManagerImple tm;
|
||||
|
||||
public static void stopTM() {
|
||||
try {
|
||||
TransactionReaper.terminate(true);
|
||||
TxControl.disable(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
tm = null;
|
||||
}
|
||||
|
||||
public static void startTM() {
|
||||
tm = new TransactionManagerImple();
|
||||
TxControl.enable();
|
||||
}
|
||||
|
||||
public TransactionManager getTM() {
|
||||
return tm;
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyXAResource implements XAResource {
|
||||
|
||||
@Override
|
||||
public void commit(Xid xid, boolean b) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(Xid xid, int i) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forget(Xid xid) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransactionTimeout() throws XAException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameRM(XAResource xaResource) throws XAException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prepare(Xid xid) throws XAException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Xid[] recover(int i) throws XAException {
|
||||
return new Xid[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(Xid xid) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTransactionTimeout(int i) throws XAException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Xid xid, int i) throws XAException {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,248 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import org.apache.activemq.artemis.json.JsonArray;
|
||||
import org.apache.activemq.artemis.json.JsonObject;
|
||||
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 org.apache.activemq.artemis.api.core.JsonUtil;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
|
||||
import org.apache.activemq.artemis.tests.integration.management.ManagementControlHelper;
|
||||
import org.apache.activemq.artemis.tests.integration.management.ManagementTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ActiveMQServerControlMultiThreadTest extends ManagementTestBase {
|
||||
|
||||
private ActiveMQServer server;
|
||||
private static volatile CountDownLatch delayCalled;
|
||||
|
||||
/**
|
||||
* Aim: verify that no exceptions will occur if deleteAddress() is invoked when listAddress() is happening
|
||||
*
|
||||
* test delays the listAddress() operations; delay after the list of addresses are retrieved but before
|
||||
* Json string (representing the addresses) is created.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "Delay listAddress() by 2 secs ",
|
||||
targetClass = "org.apache.activemq.artemis.core.postoffice.impl.PostOfficeImpl",
|
||||
targetMethod = "getAddressInfo(org.apache.activemq.artemis.api.core.SimpleString)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ActiveMQServerControlMultiThreadTest.delay(2)")})
|
||||
|
||||
public void listAddressDuringDeleteAddress() throws Exception {
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(1);
|
||||
String addressName1 = "MyAddress_one";
|
||||
String addressName2 = "MyAddress_two";
|
||||
|
||||
try {
|
||||
|
||||
//used to block thread, until the delay() has been called.
|
||||
delayCalled = new CountDownLatch(1);
|
||||
|
||||
ActiveMQServerControl serverControl = createManagementControl();
|
||||
|
||||
serverControl.createAddress(addressName1, RoutingType.ANYCAST.toString());
|
||||
serverControl.createAddress(addressName2, RoutingType.ANYCAST.toString());
|
||||
|
||||
executorService.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// wait until the listAddress has retrieved list of addresses BUT has not
|
||||
// created JSon string.
|
||||
delayCalled.await();
|
||||
serverControl.deleteAddress(addressName1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
String filter = createJsonFilter("", "", "");
|
||||
String addressesAsJsonString = serverControl.listAddresses(filter, 1, 10);
|
||||
JsonObject addressesAsJsonObject = JsonUtil.readJsonObject(addressesAsJsonString);
|
||||
JsonArray addressesArray = (JsonArray) addressesAsJsonObject.get("data");
|
||||
|
||||
// the deleteAddress() should have happened before the Json String was created
|
||||
Assert.assertEquals("number of Addresses returned from query", 1, addressesArray.size());
|
||||
Assert.assertEquals("check addresses username", addressName2.toString(), addressesArray.getJsonObject(0).getString("name"));
|
||||
|
||||
} finally {
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: verify that no exceptions will occur when a session is closed during listConsumers() operation
|
||||
*
|
||||
* test delays the listConsumer() BEFORE the Session information associated with the consumer is retrieved.
|
||||
* During this delay the client session is closed.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "Delay listConsumers() by 2 secs ",
|
||||
targetClass = "org.apache.activemq.artemis.core.management.impl.view.ConsumerView",
|
||||
targetMethod = "toJson(org.apache.activemq.artemis.core.server.ServerConsumer)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ActiveMQServerControlMultiThreadTest.delay(2)")})
|
||||
|
||||
public void listConsumersDuringSessionClose() throws Exception {
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(1);
|
||||
SimpleString addressName1 = new SimpleString("MyAddress_one");
|
||||
SimpleString queueName1 = new SimpleString("my_queue_one");
|
||||
|
||||
ActiveMQServerControl serverControl = createManagementControl();
|
||||
|
||||
server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST));
|
||||
server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST).setDurable(false));
|
||||
|
||||
// create a consumer
|
||||
try (ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(locator);
|
||||
ClientSession session = csf.createSession()) {
|
||||
|
||||
ClientConsumer consumer1_q1 = session.createConsumer(queueName1);
|
||||
|
||||
// add another consumer (on separate session)
|
||||
ClientSession session_two = csf.createSession();
|
||||
ClientConsumer consumer2_q1 = session_two.createConsumer(queueName1);
|
||||
|
||||
//first(normal) invocation - ensure 2 consumers returned
|
||||
//used to block thread, until the delay() has been called.
|
||||
delayCalled = new CountDownLatch(1);
|
||||
|
||||
String consumersAsJsonString = serverControl.listConsumers(createJsonFilter("", "", ""), 1, 10);
|
||||
|
||||
JsonObject consumersAsJsonObject = JsonUtil.readJsonObject(consumersAsJsonString);
|
||||
JsonArray consumersArray = (JsonArray) consumersAsJsonObject.get("data");
|
||||
|
||||
Assert.assertEquals("number of consumers returned from query", 2, consumersArray.size());
|
||||
Assert.assertEquals("check consumer's queue", queueName1.toString(), consumersArray.getJsonObject(0).getString("queueName"));
|
||||
Assert.assertNotEquals("check session", "", consumersArray.getJsonObject(0).getString("sessionName"));
|
||||
|
||||
//second invocation - close session during listConsumers()
|
||||
|
||||
//used to block thread, until the delay() has been called.
|
||||
delayCalled = new CountDownLatch(1);
|
||||
|
||||
executorService.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
//wait until the delay occurs and close the session.
|
||||
delayCalled.await();
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
consumersAsJsonString = serverControl.listConsumers(createJsonFilter("", "", ""), 1, 10);
|
||||
|
||||
consumersAsJsonObject = JsonUtil.readJsonObject(consumersAsJsonString);
|
||||
consumersArray = (JsonArray) consumersAsJsonObject.get("data");
|
||||
|
||||
// session is closed before Json string is created - should only be one consumer returned
|
||||
Assert.assertEquals("number of consumers returned from query", 1, consumersArray.size());
|
||||
Assert.assertEquals("check consumer's queue", queueName1.toString(), consumersArray.getJsonObject(0).getString("queueName"));
|
||||
Assert.assertNotEquals("check session", "", consumersArray.getJsonObject(0).getString("sessionName"));
|
||||
|
||||
} finally {
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
//notify delay has been called and wait for X seconds
|
||||
public static void delay(int seconds) {
|
||||
delayCalled.countDown();
|
||||
try {
|
||||
Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
Configuration config = createDefaultInVMConfig().setJMXManagementEnabled(true);
|
||||
server = createServer(false, config);
|
||||
server.setMBeanServer(mbeanServer);
|
||||
server.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
server.stop();
|
||||
|
||||
}
|
||||
|
||||
protected ActiveMQServerControl createManagementControl() throws Exception {
|
||||
return ManagementControlHelper.createActiveMQServerControl(mbeanServer);
|
||||
}
|
||||
|
||||
private String createJsonFilter(String fieldName, String operationName, String value) {
|
||||
HashMap<String, Object> filterMap = new HashMap<>();
|
||||
filterMap.put("field", fieldName);
|
||||
filterMap.put("operation", operationName);
|
||||
filterMap.put("value", value);
|
||||
JsonObject jsonFilterObject = JsonUtil.toJsonObject(filterMap);
|
||||
return jsonFilterObject.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class AddressDeploymentFailedTest extends ActiveMQTestBase {
|
||||
|
||||
@Test
|
||||
@BMRule(name = "blow up address deployment",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl",
|
||||
targetMethod = "addOrUpdateAddressInfo(AddressInfo)",
|
||||
targetLocation = "EXIT",
|
||||
action = "throw new IllegalStateException(\"test exception\")")
|
||||
public void testAddressDeploymentFailure() throws Exception {
|
||||
ActiveMQServer server = createServer(false, createDefaultNettyConfig());
|
||||
server.getConfiguration().addAddressConfiguration(new CoreAddressConfiguration().setName(UUID.randomUUID().toString()).addRoutingType(RoutingType.ANYCAST));
|
||||
server.start();
|
||||
assertTrue(server.getRemotingService().isStarted());
|
||||
}
|
||||
}
|
|
@ -1,368 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.transaction.xa.XAException;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import javax.transaction.xa.Xid;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQTransactionOutcomeUnknownException;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQTransactionRolledBackException;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQUnBlockedException;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.client.ActiveMQClientMessageBundle;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientMessageImpl;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionInternal;
|
||||
import org.apache.activemq.artemis.core.postoffice.Binding;
|
||||
import org.apache.activemq.artemis.core.server.Queue;
|
||||
import org.apache.activemq.artemis.core.transaction.impl.XidImpl;
|
||||
import org.apache.activemq.artemis.tests.integration.cluster.failover.FailoverTestBase;
|
||||
import org.apache.activemq.artemis.tests.integration.cluster.util.TestableServer;
|
||||
import org.apache.activemq.artemis.tests.util.RandomUtil;
|
||||
import org.apache.activemq.artemis.utils.UUIDGenerator;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class BMFailoverTest extends FailoverTestBase {
|
||||
private static final Logger log = Logger.getLogger(BMFailoverTest.class);
|
||||
|
||||
private ServerLocator locator;
|
||||
private ClientSessionFactoryInternal sf;
|
||||
private ClientSessionFactoryInternal sf2;
|
||||
public static TestableServer serverToStop;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
stopped = false;
|
||||
locator = getServerLocator();
|
||||
}
|
||||
|
||||
private static boolean stopped = false;
|
||||
|
||||
public static void stopAndThrow() throws ActiveMQUnBlockedException {
|
||||
if (!stopped) {
|
||||
try {
|
||||
serverToStop.getServer().fail(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
stopped = true;
|
||||
throw ActiveMQClientMessageBundle.BUNDLE.unblockingACall(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "trace ActiveMQSessionContext xaEnd",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext",
|
||||
targetMethod = "xaEnd",
|
||||
targetLocation = "AT EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.BMFailoverTest.stopAndThrow()")})
|
||||
//https://bugzilla.redhat.com/show_bug.cgi?id=1152410
|
||||
public void testFailOnEndAndRetry() throws Exception {
|
||||
serverToStop = liveServer;
|
||||
|
||||
createSessionFactory();
|
||||
|
||||
ClientSession session = createSession(sf, true, false, false);
|
||||
|
||||
session.createQueue(new QueueConfiguration(FailoverTestBase.ADDRESS));
|
||||
|
||||
ClientProducer producer = session.createProducer(FailoverTestBase.ADDRESS);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
producer.send(createMessage(session, i, true));
|
||||
}
|
||||
|
||||
ClientConsumer consumer = session.createConsumer(FailoverTestBase.ADDRESS);
|
||||
|
||||
Xid xid = RandomUtil.randomXid();
|
||||
|
||||
session.start(xid, XAResource.TMNOFLAGS);
|
||||
session.start();
|
||||
// Receive MSGs but don't ack!
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ClientMessage message = consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(message);
|
||||
|
||||
assertMessageBody(i, message);
|
||||
|
||||
Assert.assertEquals(i, message.getIntProperty("counter").intValue());
|
||||
}
|
||||
try {
|
||||
//top level prepare
|
||||
session.end(xid, XAResource.TMSUCCESS);
|
||||
} catch (XAException e) {
|
||||
try {
|
||||
//top level abort
|
||||
session.end(xid, XAResource.TMFAIL);
|
||||
} catch (XAException e1) {
|
||||
try {
|
||||
//rollback
|
||||
session.rollback(xid);
|
||||
} catch (XAException e2) {
|
||||
}
|
||||
}
|
||||
}
|
||||
xid = RandomUtil.randomXid();
|
||||
session.start(xid, XAResource.TMNOFLAGS);
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
ClientMessage message = consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(message);
|
||||
|
||||
assertMessageBody(i, message);
|
||||
|
||||
Assert.assertEquals(i, message.getIntProperty("counter").intValue());
|
||||
}
|
||||
session.end(xid, XAResource.TMSUCCESS);
|
||||
session.commit(xid, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "trace clientsessionimpl commit",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientSessionImpl",
|
||||
targetMethod = "start(javax.transaction.xa.Xid, int)",
|
||||
targetLocation = "AT EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.BMFailoverTest.serverToStop.getServer().stop(true)")})
|
||||
public void testFailoverOnCommit2() throws Exception {
|
||||
serverToStop = liveServer;
|
||||
locator = getServerLocator();
|
||||
SimpleString inQueue = new SimpleString("inQueue");
|
||||
SimpleString outQueue = new SimpleString("outQueue");
|
||||
createSessionFactory();
|
||||
createSessionFactory2();
|
||||
|
||||
// closeable will take care of closing it
|
||||
try (ClientSession session = sf.createSession(false, true, true);
|
||||
ClientProducer sendInitialProducer = session.createProducer();) {
|
||||
session.createQueue(new QueueConfiguration(inQueue));
|
||||
session.createQueue(new QueueConfiguration(outQueue));
|
||||
sendInitialProducer.send(inQueue, createMessage(session, 0, true));
|
||||
}
|
||||
|
||||
ClientSession xaSessionRec = addClientSession(sf.createSession(true, false, false));
|
||||
|
||||
ClientConsumer consumer = addClientConsumer(xaSessionRec.createConsumer(inQueue));
|
||||
|
||||
byte[] globalTransactionId = UUIDGenerator.getInstance().generateStringUUID().getBytes();
|
||||
Xid xidRec = new XidImpl("xa2".getBytes(), 1, globalTransactionId);
|
||||
|
||||
xaSessionRec.start();
|
||||
|
||||
xaSessionRec.getXAResource().start(xidRec, XAResource.TMNOFLAGS);
|
||||
|
||||
//failover is now occurring, receive, ack and end will be called whilst this is happening.
|
||||
|
||||
ClientMessageImpl m = (ClientMessageImpl) consumer.receive(5000);
|
||||
|
||||
assertNotNull(m);
|
||||
|
||||
log.debug("********************" + m.getIntProperty("counter"));
|
||||
//the mdb would ack the message before calling onMessage()
|
||||
m.acknowledge();
|
||||
|
||||
try {
|
||||
//this may fail but thats ok, it depends on the race and when failover actually happens
|
||||
xaSessionRec.end(xidRec, XAResource.TMSUCCESS);
|
||||
} catch (XAException ignore) {
|
||||
}
|
||||
|
||||
//we always reset the client on the RA
|
||||
((ClientSessionInternal) xaSessionRec).resetIfNeeded();
|
||||
|
||||
// closeable will take care of closing it
|
||||
try (ClientSession session = sf.createSession(false, true, true);
|
||||
ClientProducer sendInitialProducer = session.createProducer();) {
|
||||
sendInitialProducer.send(inQueue, createMessage(session, 0, true));
|
||||
}
|
||||
|
||||
//now receive and send a message successfully
|
||||
|
||||
globalTransactionId = UUIDGenerator.getInstance().generateStringUUID().getBytes();
|
||||
xidRec = new XidImpl("xa4".getBytes(), 1, globalTransactionId);
|
||||
xaSessionRec.getXAResource().start(xidRec, XAResource.TMNOFLAGS);
|
||||
|
||||
Binding binding = backupServer.getServer().getPostOffice().getBinding(inQueue);
|
||||
Queue inQ = (Queue) binding.getBindable();
|
||||
|
||||
m = (ClientMessageImpl) consumer.receive(5000);
|
||||
|
||||
assertNotNull(m);
|
||||
//the mdb would ack the message before calling onMessage()
|
||||
m.acknowledge();
|
||||
|
||||
log.debug("********************" + m.getIntProperty("counter"));
|
||||
|
||||
xaSessionRec.getXAResource().end(xidRec, XAResource.TMSUCCESS);
|
||||
xaSessionRec.getXAResource().prepare(xidRec);
|
||||
xaSessionRec.getXAResource().commit(xidRec, false);
|
||||
|
||||
//let's close the consumer so anything pending is handled
|
||||
consumer.close();
|
||||
|
||||
assertEquals(1, getMessageCount(inQ));
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "trace clientsessionimpl commit",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientSessionImpl",
|
||||
targetMethod = "commit",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.BMFailoverTest.serverToStop.getServer().stop(true)")})
|
||||
public void testFailoverOnCommit() throws Exception {
|
||||
serverToStop = liveServer;
|
||||
locator = getServerLocator();
|
||||
createSessionFactory();
|
||||
ClientSession session = createSessionAndQueue();
|
||||
|
||||
ClientProducer producer = addClientProducer(session.createProducer(FailoverTestBase.ADDRESS));
|
||||
|
||||
sendMessages(session, producer, 10);
|
||||
try {
|
||||
session.commit();
|
||||
fail("should have thrown an exception");
|
||||
} catch (ActiveMQTransactionOutcomeUnknownException e) {
|
||||
//pass
|
||||
}
|
||||
sendMessages(session, producer, 10);
|
||||
session.commit();
|
||||
Queue bindable = (Queue) backupServer.getServer().getPostOffice().getBinding(FailoverTestBase.ADDRESS).getBindable();
|
||||
assertEquals(10, getMessageCount(bindable));
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "trace clientsessionimpl commit",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientSessionImpl",
|
||||
targetMethod = "commit",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.BMFailoverTest.serverToStop.getServer().stop(true)")})
|
||||
public void testFailoverOnReceiveCommit() throws Exception {
|
||||
serverToStop = liveServer;
|
||||
locator = getServerLocator();
|
||||
createSessionFactory();
|
||||
ClientSession session = createSessionAndQueue();
|
||||
|
||||
ClientSession sendSession = createSession(sf, true, true);
|
||||
|
||||
ClientProducer producer = addClientProducer(sendSession.createProducer(FailoverTestBase.ADDRESS));
|
||||
|
||||
sendMessages(sendSession, producer, 10);
|
||||
|
||||
ClientConsumer consumer = session.createConsumer(FailoverTestBase.ADDRESS);
|
||||
session.start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ClientMessage m = consumer.receive(500);
|
||||
assertNotNull(m);
|
||||
m.acknowledge();
|
||||
}
|
||||
try {
|
||||
session.commit();
|
||||
fail("should have thrown an exception");
|
||||
} catch (ActiveMQTransactionOutcomeUnknownException e) {
|
||||
//pass
|
||||
} catch (ActiveMQTransactionRolledBackException e1) {
|
||||
//pass
|
||||
}
|
||||
Queue bindable = (Queue) backupServer.getServer().getPostOffice().getBinding(FailoverTestBase.ADDRESS).getBindable();
|
||||
assertEquals(10, getMessageCount(bindable));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransportConfiguration getAcceptorTransportConfiguration(final boolean live) {
|
||||
return getNettyAcceptorTransportConfiguration(live);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransportConfiguration getConnectorTransportConfiguration(final boolean live) {
|
||||
return getNettyConnectorTransportConfiguration(live);
|
||||
}
|
||||
|
||||
private ClientSession createSessionAndQueue() throws Exception {
|
||||
ClientSession session = createSession(sf, false, false);
|
||||
|
||||
session.createQueue(new QueueConfiguration(FailoverTestBase.ADDRESS));
|
||||
return session;
|
||||
}
|
||||
|
||||
private ClientSession createXASessionAndQueue() throws Exception {
|
||||
ClientSession session = addClientSession(sf.createSession(true, true, true));
|
||||
|
||||
session.createQueue(new QueueConfiguration(FailoverTestBase.ADDRESS));
|
||||
return session;
|
||||
}
|
||||
|
||||
protected ClientSession createSession(ClientSessionFactory sf1,
|
||||
boolean autoCommitSends,
|
||||
boolean autoCommitAcks) throws Exception {
|
||||
return addClientSession(sf1.createSession(autoCommitSends, autoCommitAcks));
|
||||
}
|
||||
|
||||
protected ClientSession createSession(ClientSessionFactory sf1,
|
||||
boolean xa,
|
||||
boolean autoCommitSends,
|
||||
boolean autoCommitAcks) throws Exception {
|
||||
return addClientSession(sf1.createSession(xa, autoCommitSends, autoCommitAcks));
|
||||
}
|
||||
|
||||
private void createSessionFactory() throws Exception {
|
||||
locator.setBlockOnNonDurableSend(true).setBlockOnDurableSend(true).setReconnectAttempts(15);
|
||||
|
||||
sf = createSessionFactoryAndWaitForTopology(locator, 2);
|
||||
}
|
||||
|
||||
private void createSessionFactory2() throws Exception {
|
||||
sf2 = createSessionFactoryAndWaitForTopology(locator, 2);
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.BridgeConfiguration;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.BridgeImpl;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class BridgeServerLocatorConfigurationTest extends ActiveMQTestBase {
|
||||
|
||||
private static final long BRIDGE_TTL = 1234L;
|
||||
private static final String BRIDGE_NAME = "bridge1";
|
||||
|
||||
protected boolean isNetty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getConnector() {
|
||||
if (isNetty()) {
|
||||
return NETTY_CONNECTOR_FACTORY;
|
||||
}
|
||||
return INVM_CONNECTOR_FACTORY;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRule(name = "check connection ttl",
|
||||
targetClass = "org.apache.activemq.artemis.tests.extras.byteman.BridgeServerLocatorConfigurationTest",
|
||||
targetMethod = "getBridgeTTL(ActiveMQServer, String)", targetLocation = "EXIT",
|
||||
action = "$! = $0.getConfiguredBridge($1).serverLocator.getConnectionTTL();")
|
||||
/**
|
||||
* Checks the connection ttl by using byteman to override the methods on this class to return the value of private variables in the Bridge.
|
||||
* @throws Exception
|
||||
*
|
||||
* The byteman rule on this test overwrites the {@link #getBridgeTTL} method to retrieve the bridge called {@link @BRIDGE_NAME}.
|
||||
* It the overrides the return value to be the value of the connection ttl. Note that the unused String parameter is required to
|
||||
* ensure that byteman populates the $1 variable, otherwise it will not bind correctly.
|
||||
*/ public void testConnectionTTLOnBridge() throws Exception {
|
||||
Map<String, Object> server0Params = new HashMap<>();
|
||||
ActiveMQServer serverWithBridge = createClusteredServerWithParams(isNetty(), 0, true, server0Params);
|
||||
|
||||
Map<String, Object> server1Params = new HashMap<>();
|
||||
if (isNetty()) {
|
||||
server1Params.put("port", org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.DEFAULT_PORT + 1);
|
||||
} else {
|
||||
server1Params.put(TransportConstants.SERVER_ID_PROP_NAME, 1);
|
||||
}
|
||||
ActiveMQServer server1 = createClusteredServerWithParams(isNetty(), 1, true, server1Params);
|
||||
try {
|
||||
final String testAddress = "testAddress";
|
||||
final String queueName0 = "queue0";
|
||||
final String forwardAddress = "forwardAddress";
|
||||
final String queueName1 = "queue1";
|
||||
|
||||
Map<String, TransportConfiguration> connectors = new HashMap<>();
|
||||
TransportConfiguration server1tc = new TransportConfiguration(getConnector(), server1Params);
|
||||
connectors.put(server1tc.getName(), server1tc);
|
||||
|
||||
serverWithBridge.getConfiguration().setConnectorConfigurations(connectors);
|
||||
|
||||
ArrayList<String> staticConnectors = new ArrayList<>();
|
||||
staticConnectors.add(server1tc.getName());
|
||||
|
||||
BridgeConfiguration bridgeConfiguration = new BridgeConfiguration().setName(BRIDGE_NAME).setQueueName(queueName0).setForwardingAddress(forwardAddress).setConnectionTTL(BRIDGE_TTL).setRetryInterval(1000).setReconnectAttempts(0).setReconnectAttemptsOnSameNode(0).setConfirmationWindowSize(1024).setStaticConnectors(staticConnectors);
|
||||
|
||||
List<BridgeConfiguration> bridgeConfigs = new ArrayList<>();
|
||||
bridgeConfigs.add(bridgeConfiguration);
|
||||
serverWithBridge.getConfiguration().setBridgeConfigurations(bridgeConfigs);
|
||||
|
||||
serverWithBridge.getConfiguration().addQueueConfiguration(new QueueConfiguration(queueName0).setAddress(testAddress));
|
||||
|
||||
server1.getConfiguration().addQueueConfiguration(new QueueConfiguration(queueName1).setAddress(forwardAddress));
|
||||
|
||||
server1.start();
|
||||
waitForServerToStart(server1);
|
||||
|
||||
serverWithBridge.start();
|
||||
waitForServerToStart(serverWithBridge);
|
||||
|
||||
long bridgeTTL = getBridgeTTL(serverWithBridge, BRIDGE_NAME);
|
||||
|
||||
assertEquals(BRIDGE_TTL, bridgeTTL);
|
||||
} finally {
|
||||
serverWithBridge.stop();
|
||||
|
||||
server1.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for byteman to wrap around and do its magic with to return the ttl from private members
|
||||
* rather than -1
|
||||
*
|
||||
* @param bridgeServer
|
||||
* @param bridgeName
|
||||
* @return
|
||||
*/
|
||||
private long getBridgeTTL(ActiveMQServer bridgeServer, String bridgeName) {
|
||||
return -1L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Byteman seems to need this method so that it gets back the concrete type not the interface
|
||||
*
|
||||
* @param bridgeServer
|
||||
* @return
|
||||
*/
|
||||
private BridgeImpl getConfiguredBridge(ActiveMQServer bridgeServer) {
|
||||
return getConfiguredBridge(bridgeServer, BRIDGE_NAME);
|
||||
}
|
||||
|
||||
private BridgeImpl getConfiguredBridge(ActiveMQServer bridgeServer, String bridgeName) {
|
||||
return (BridgeImpl) bridgeServer.getClusterManager().getBridges().get(bridgeName);
|
||||
}
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.management.CoreNotificationType;
|
||||
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
|
||||
import org.apache.activemq.artemis.core.server.cluster.MessageFlowRecord;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.ClusterConnectionBridge;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.ClusterConnectionImpl;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
|
||||
import org.apache.activemq.artemis.core.server.management.Notification;
|
||||
import org.apache.activemq.artemis.tests.integration.cluster.distribution.ClusterTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This will simulate a failure of a failure.
|
||||
* The bridge could eventually during a race or multiple failures not be able to reconnect because it failed again.
|
||||
* this should make the bridge to always reconnect itself.
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ClusteredBridgeReconnectTest extends ClusterTestBase {
|
||||
|
||||
static ThreadLocal<Boolean> inConnect = new ThreadLocal<>();
|
||||
|
||||
public static void enterConnect() {
|
||||
inConnect.set(Boolean.TRUE);
|
||||
}
|
||||
|
||||
public static void exitConnect() {
|
||||
inConnect.set(null);
|
||||
}
|
||||
|
||||
public static volatile boolean shouldFail = false;
|
||||
|
||||
public static void send() {
|
||||
if (inConnect.get() != null) {
|
||||
if (shouldFail) {
|
||||
shouldFail = false;
|
||||
throw new NullPointerException("just because it's a test...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "enter",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.cluster.impl.BridgeImpl",
|
||||
targetMethod = "connect",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredBridgeReconnectTest.enterConnect();"),
|
||||
@BMRule(
|
||||
name = "exit",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.cluster.impl.BridgeImpl",
|
||||
targetMethod = "connect",
|
||||
targetLocation = "EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredBridgeReconnectTest.exitConnect();"),
|
||||
@BMRule(
|
||||
name = "send",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl",
|
||||
targetMethod = "send(org.apache.activemq.artemis.core.protocol.core.Packet)",
|
||||
targetLocation = "EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredBridgeReconnectTest.send();")})
|
||||
public void testReconnectBridge() throws Exception {
|
||||
setupServer(0, isFileStorage(), isNetty());
|
||||
setupServer(1, isFileStorage(), isNetty());
|
||||
|
||||
setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 0, 1);
|
||||
|
||||
setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 1, 0);
|
||||
|
||||
startServers(0, 1);
|
||||
|
||||
setupSessionFactory(0, isNetty());
|
||||
setupSessionFactory(1, isNetty());
|
||||
|
||||
createQueue(0, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(1, "queues.testaddress", "queue0", null, true);
|
||||
|
||||
addConsumer(0, 0, "queue0", null);
|
||||
addConsumer(1, 1, "queue0", null);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 1, 1, true);
|
||||
waitForBindings(1, "queues.testaddress", 1, 1, true);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 1, 1, false);
|
||||
waitForBindings(1, "queues.testaddress", 1, 1, false);
|
||||
|
||||
ClientSession session0 = sfs[0].createSession();
|
||||
ClientSession session1 = sfs[0].createSession();
|
||||
|
||||
session0.start();
|
||||
session1.start();
|
||||
|
||||
ClientProducer producer = session0.createProducer("queues.testaddress");
|
||||
|
||||
int NUMBER_OF_MESSAGES = 100;
|
||||
|
||||
Assert.assertEquals(1, servers[0].getClusterManager().getClusterConnections().size());
|
||||
|
||||
ClusterConnectionImpl connection = servers[0].getClusterManager().getClusterConnections().toArray(new ClusterConnectionImpl[0])[0];
|
||||
Assert.assertEquals(1, connection.getRecords().size());
|
||||
|
||||
MessageFlowRecord record = connection.getRecords().values().toArray(new MessageFlowRecord[1])[0];
|
||||
ClusterConnectionBridge bridge = (ClusterConnectionBridge) record.getBridge();
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
|
||||
ClientMessage msg = session0.createMessage(true);
|
||||
producer.send(msg);
|
||||
session0.commit();
|
||||
|
||||
if (i == 17) {
|
||||
shouldFail = true;
|
||||
bridge.getSessionFactory().getConnection().fail(new ActiveMQException("failed once!"));
|
||||
}
|
||||
}
|
||||
|
||||
int cons0Count = 0, cons1Count = 0;
|
||||
|
||||
while (true) {
|
||||
ClientMessage msg = consumers[0].getConsumer().receive(1000);
|
||||
if (msg == null) {
|
||||
break;
|
||||
}
|
||||
cons0Count++;
|
||||
msg.acknowledge();
|
||||
session0.commit();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
ClientMessage msg = consumers[1].getConsumer().receive(1000);
|
||||
if (msg == null) {
|
||||
break;
|
||||
}
|
||||
cons1Count++;
|
||||
msg.acknowledge();
|
||||
session1.commit();
|
||||
}
|
||||
|
||||
Assert.assertEquals("cons0 = " + cons0Count + ", cons1 = " + cons1Count, NUMBER_OF_MESSAGES, cons0Count + cons1Count);
|
||||
|
||||
session0.commit();
|
||||
session1.commit();
|
||||
|
||||
stopServers(0, 1);
|
||||
|
||||
}
|
||||
|
||||
static CountDownLatch latch;
|
||||
static CountDownLatch latch2;
|
||||
static Thread main;
|
||||
|
||||
public static void pause(SimpleString clusterName) {
|
||||
if (clusterName.toString().startsWith("queue0")) {
|
||||
try {
|
||||
latch2.countDown();
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void pause2(Notification notification) {
|
||||
if (notification.getType() == CoreNotificationType.BINDING_REMOVED) {
|
||||
SimpleString clusterName = notification.getProperties().getSimpleStringProperty(ManagementHelper.HDR_CLUSTER_NAME);
|
||||
boolean inMain = main == Thread.currentThread();
|
||||
if (clusterName.toString().startsWith("queue0") && !inMain) {
|
||||
try {
|
||||
latch2.countDown();
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void restart2() {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
shouldFail = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
closeAllConsumers();
|
||||
closeAllSessionFactories();
|
||||
closeAllServerLocatorsFactories();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public boolean isNetty() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,380 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException;
|
||||
import org.apache.activemq.artemis.api.core.Message;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.management.CoreNotificationType;
|
||||
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
|
||||
import org.apache.activemq.artemis.core.server.group.impl.GroupingHandlerConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.group.impl.Response;
|
||||
import org.apache.activemq.artemis.core.server.management.Notification;
|
||||
import org.apache.activemq.artemis.tests.integration.cluster.distribution.ClusterTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ClusteredGroupingTest extends ClusterTestBase {
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "blow-up",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.LocalGroupingHandler",
|
||||
targetMethod = "removeGrouping",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.pause($1);"),
|
||||
@BMRule(
|
||||
name = "blow-up2",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.GroupHandlingAbstract",
|
||||
targetMethod = "forceRemove",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.restart2();")})
|
||||
public void test2serversLocalGoesDown() throws Exception {
|
||||
setupServer(0, isFileStorage(), isNetty());
|
||||
setupServer(1, isFileStorage(), isNetty());
|
||||
|
||||
setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 0, 1);
|
||||
|
||||
setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 1, 0);
|
||||
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.LOCAL, 0);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 1);
|
||||
|
||||
startServers(0, 1);
|
||||
|
||||
setupSessionFactory(0, isNetty());
|
||||
setupSessionFactory(1, isNetty());
|
||||
|
||||
createQueue(0, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(1, "queues.testaddress", "queue0", null, true);
|
||||
|
||||
addConsumer(0, 1, "queue0", null);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(1, "queues.testaddress", 1, 1, true);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 1, 1, false);
|
||||
waitForBindings(1, "queues.testaddress", 1, 0, false);
|
||||
|
||||
sendWithProperty(0, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
latch2 = new CountDownLatch(1);
|
||||
|
||||
crashAndWaitForFailure(getServer(1));
|
||||
|
||||
assertTrue(latch2.await(20000, TimeUnit.MILLISECONDS));
|
||||
|
||||
try {
|
||||
try {
|
||||
sendWithProperty(0, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
} catch (ActiveMQNonExistentQueueException e) {
|
||||
fail("did not handle removal of queue");
|
||||
}
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "blow-up",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.RemoteGroupingHandler",
|
||||
targetMethod = "onNotification",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.pause2($1);"),
|
||||
@BMRule(name = "blow-up2",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.RemoteGroupingHandler",
|
||||
targetMethod = "remove",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.restart2();")})
|
||||
public void test3serversLocalGoesDown() throws Exception {
|
||||
setupServer(0, isFileStorage(), isNetty());
|
||||
setupServer(1, isFileStorage(), isNetty());
|
||||
setupServer(2, isFileStorage(), isNetty());
|
||||
|
||||
setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 0, 1, 2);
|
||||
|
||||
setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 1, 0, 2);
|
||||
|
||||
setupClusterConnection("cluster2", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 2, 0, 1);
|
||||
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.LOCAL, 0);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 1);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 2);
|
||||
|
||||
startServers(0, 1, 2);
|
||||
|
||||
setupSessionFactory(0, isNetty());
|
||||
setupSessionFactory(1, isNetty());
|
||||
setupSessionFactory(2, isNetty());
|
||||
|
||||
createQueue(0, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(1, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(2, "queues.testaddress", "queue0", null, true);
|
||||
|
||||
addConsumer(0, 2, "queue0", null);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(1, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(2, "queues.testaddress", 1, 1, true);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 2, 1, false);
|
||||
waitForBindings(1, "queues.testaddress", 2, 1, false);
|
||||
waitForBindings(2, "queues.testaddress", 2, 0, false);
|
||||
|
||||
sendWithProperty(1, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
latch2 = new CountDownLatch(1);
|
||||
|
||||
main = Thread.currentThread();
|
||||
crashAndWaitForFailure(getServer(2));
|
||||
|
||||
assertTrue(latch2.await(20000, TimeUnit.MILLISECONDS));
|
||||
|
||||
try {
|
||||
try {
|
||||
sendWithProperty(1, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
} catch (ActiveMQNonExistentQueueException e) {
|
||||
fail("did not handle removal of queue");
|
||||
}
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
assertHandlersAreSame(getServer(0), getServer(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "blow-up",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.LocalGroupingHandler",
|
||||
targetMethod = "onNotification",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.pause2($1);"),
|
||||
@BMRule(name = "blow-up2",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.LocalGroupingHandler",
|
||||
targetMethod = "remove",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.restart2();")})
|
||||
public void testLocal3serversLocalGoesDown() throws Exception {
|
||||
setupServer(0, isFileStorage(), isNetty());
|
||||
setupServer(1, isFileStorage(), isNetty());
|
||||
setupServer(2, isFileStorage(), isNetty());
|
||||
|
||||
setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 0, 1, 2);
|
||||
|
||||
setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 1, 0, 2);
|
||||
|
||||
setupClusterConnection("cluster2", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 2, 0, 1);
|
||||
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.LOCAL, 0);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 1);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 2);
|
||||
|
||||
startServers(0, 1, 2);
|
||||
|
||||
setupSessionFactory(0, isNetty());
|
||||
setupSessionFactory(1, isNetty());
|
||||
setupSessionFactory(2, isNetty());
|
||||
|
||||
createQueue(0, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(1, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(2, "queues.testaddress", "queue0", null, true);
|
||||
|
||||
addConsumer(0, 2, "queue0", null);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(1, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(2, "queues.testaddress", 1, 1, true);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 2, 1, false);
|
||||
waitForBindings(1, "queues.testaddress", 2, 1, false);
|
||||
waitForBindings(2, "queues.testaddress", 2, 0, false);
|
||||
|
||||
sendWithProperty(0, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
latch2 = new CountDownLatch(1);
|
||||
|
||||
main = Thread.currentThread();
|
||||
crashAndWaitForFailure(getServer(2));
|
||||
|
||||
assertTrue(latch2.await(20000, TimeUnit.MILLISECONDS));
|
||||
|
||||
try {
|
||||
try {
|
||||
sendWithProperty(0, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
} catch (ActiveMQNonExistentQueueException e) {
|
||||
fail("did not handle removal of queue");
|
||||
}
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
assertHandlersAreSame(getServer(0), getServer(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "blow-up",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.LocalGroupingHandler",
|
||||
targetMethod = "onNotification",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.pause2($1);"),
|
||||
@BMRule(name = "blow-up2",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.group.impl.LocalGroupingHandler",
|
||||
targetMethod = "remove",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredGroupingTest.restart2();")})
|
||||
public void testLocal4serversLocalGoesDown() throws Exception {
|
||||
setupServer(0, isFileStorage(), isNetty());
|
||||
setupServer(1, isFileStorage(), isNetty());
|
||||
setupServer(2, isFileStorage(), isNetty());
|
||||
setupServer(3, isFileStorage(), isNetty());
|
||||
|
||||
setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 0, 1, 2, 3);
|
||||
|
||||
setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 1, 0, 2, 3);
|
||||
|
||||
setupClusterConnection("cluster2", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 2, 0, 1, 3);
|
||||
|
||||
setupClusterConnection("cluster3", "queues", MessageLoadBalancingType.ON_DEMAND, 1, -1, 500, isNetty(), 3, 1, 2, 3);
|
||||
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.LOCAL, 0);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 1);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 2);
|
||||
setUpGroupHandler(GroupingHandlerConfiguration.TYPE.REMOTE, 3);
|
||||
|
||||
startServers(0, 1, 2, 3);
|
||||
|
||||
setupSessionFactory(0, isNetty());
|
||||
setupSessionFactory(1, isNetty());
|
||||
setupSessionFactory(2, isNetty());
|
||||
setupSessionFactory(3, isNetty());
|
||||
|
||||
createQueue(0, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(1, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(2, "queues.testaddress", "queue0", null, true);
|
||||
createQueue(3, "queues.testaddress", "queue0", null, true);
|
||||
|
||||
addConsumer(0, 2, "queue0", null);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(1, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(2, "queues.testaddress", 1, 1, true);
|
||||
waitForBindings(3, "queues.testaddress", 1, 0, true);
|
||||
|
||||
waitForBindings(0, "queues.testaddress", 3, 1, false);
|
||||
waitForBindings(1, "queues.testaddress", 3, 1, false);
|
||||
waitForBindings(2, "queues.testaddress", 3, 0, false);
|
||||
waitForBindings(3, "queues.testaddress", 3, 1, false);
|
||||
|
||||
sendWithProperty(0, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
latch2 = new CountDownLatch(1);
|
||||
|
||||
main = Thread.currentThread();
|
||||
crashAndWaitForFailure(getServer(2));
|
||||
|
||||
assertTrue(latch2.await(20000, TimeUnit.MILLISECONDS));
|
||||
|
||||
try {
|
||||
try {
|
||||
sendWithProperty(0, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
} catch (ActiveMQNonExistentQueueException e) {
|
||||
fail("did not handle removal of queue");
|
||||
}
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
//now restart server
|
||||
getServer(2).start();
|
||||
waitForBindings(2, "queues.testaddress", 1, 0, true);
|
||||
waitForBindings(2, "queues.testaddress", 3, 0, false);
|
||||
sendWithProperty(3, "queues.testaddress", 1, true, Message.HDR_GROUP_ID, new SimpleString("id1"));
|
||||
Thread.sleep(2000);
|
||||
assertHandlersAreSame(getServer(0), getServer(1), getServer(2), getServer(3));
|
||||
}
|
||||
|
||||
private void assertHandlersAreSame(ActiveMQServer server, ActiveMQServer... qServers) {
|
||||
SimpleString id = server.getGroupingHandler().getProposal(new SimpleString("id1.queue0"), false).getClusterName();
|
||||
for (ActiveMQServer qServer : qServers) {
|
||||
Response proposal = qServer.getGroupingHandler().getProposal(new SimpleString("id1.queue0"), false);
|
||||
if (proposal != null) {
|
||||
assertEquals(qServer.getIdentity() + " is incorrect", id, proposal.getChosenClusterName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CountDownLatch latch;
|
||||
static CountDownLatch latch2;
|
||||
static Thread main;
|
||||
|
||||
public static void pause(SimpleString clusterName) {
|
||||
if (clusterName.toString().startsWith("queue0")) {
|
||||
try {
|
||||
latch2.countDown();
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void pause2(Notification notification) {
|
||||
if (notification.getType() == CoreNotificationType.BINDING_REMOVED) {
|
||||
SimpleString clusterName = notification.getProperties().getSimpleStringProperty(ManagementHelper.HDR_CLUSTER_NAME);
|
||||
boolean inMain = main == Thread.currentThread();
|
||||
if (clusterName.toString().startsWith("queue0") && !inMain) {
|
||||
try {
|
||||
latch2.countDown();
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void restart2() {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
public boolean isNetty() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,259 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p/>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
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 java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||
import org.apache.activemq.artemis.core.server.ServerSession;
|
||||
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
|
||||
import org.apache.activemq.artemis.core.transaction.impl.XidImpl;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQSession;
|
||||
import org.apache.activemq.artemis.tests.util.JMSTestBase;
|
||||
import org.apache.activemq.artemis.utils.RandomUtil;
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This test will force two consumers to be waiting on close and introduce a race I saw in a production system
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ConcurrentDeliveryCancelTest extends JMSTestBase {
|
||||
private static final Logger log = Logger.getLogger(ConcurrentDeliveryCancelTest.class);
|
||||
|
||||
// used to wait the thread to align at the same place and create the race
|
||||
private static final ReusableLatch latchEnter = new ReusableLatch(2);
|
||||
// used to start
|
||||
private static final ReusableLatch latchFlag = new ReusableLatch(1);
|
||||
|
||||
public static void enterCancel() {
|
||||
try {
|
||||
latchEnter.countDown();
|
||||
latchFlag.await(1, TimeUnit.SECONDS);
|
||||
} catch (Throwable ignored) {
|
||||
ignored.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetLatches(int numberOfThreads) {
|
||||
latchEnter.setCount(numberOfThreads);
|
||||
latchFlag.setCount(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean usePersistence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "enterCancel-holdThere",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl",
|
||||
targetMethod = "close",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ConcurrentDeliveryCancelTest.enterCancel();")})
|
||||
public void testConcurrentCancels() throws Exception {
|
||||
|
||||
log.debug(server.getConfiguration().getJournalLocation().toString());
|
||||
server.getAddressSettingsRepository().clear();
|
||||
AddressSettings settings = new AddressSettings();
|
||||
settings.setMaxDeliveryAttempts(-1);
|
||||
server.getAddressSettingsRepository().addMatch("#", settings);
|
||||
ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactory("tcp://localhost:61616", "test");
|
||||
cf.setReconnectAttempts(0);
|
||||
cf.setRetryInterval(10);
|
||||
|
||||
log.debug(".....");
|
||||
for (ServerSession srvSess : server.getSessions()) {
|
||||
log.debug(srvSess);
|
||||
}
|
||||
|
||||
String queueName = RandomUtil.randomString();
|
||||
Queue queue = createQueue(queueName);
|
||||
|
||||
int numberOfMessages = 100;
|
||||
|
||||
{
|
||||
Connection connection = cf.createConnection();
|
||||
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
|
||||
MessageProducer producer = session.createProducer(queue);
|
||||
|
||||
for (int i = 0; i < numberOfMessages; i++) {
|
||||
TextMessage msg = session.createTextMessage("message " + i);
|
||||
msg.setIntProperty("i", i);
|
||||
producer.send(msg);
|
||||
}
|
||||
session.commit();
|
||||
|
||||
connection.close();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
XAConnectionFactory xacf = ActiveMQJMSClient.createConnectionFactory("tcp://localhost:61616", "test");
|
||||
|
||||
final XAConnection connection = xacf.createXAConnection();
|
||||
final XASession theSession = connection.createXASession();
|
||||
((ActiveMQSession) theSession).getCoreSession().addMetaData("theSession", "true");
|
||||
|
||||
connection.start();
|
||||
|
||||
final MessageConsumer consumer = theSession.createConsumer(queue);
|
||||
|
||||
XidImpl xid = newXID();
|
||||
theSession.getXAResource().start(xid, XAResource.TMNOFLAGS);
|
||||
theSession.getXAResource().setTransactionTimeout(1); // I'm setting a small timeout just because I'm lazy to call end myself
|
||||
|
||||
for (int msg = 0; msg < 11; msg++) {
|
||||
Assert.assertNotNull(consumer.receiveNoWait());
|
||||
}
|
||||
|
||||
log.debug(".....");
|
||||
|
||||
final List<ServerSession> serverSessions = new LinkedList<>();
|
||||
|
||||
// We will force now the failure simultaneously from several places
|
||||
for (ServerSession srvSess : server.getSessions()) {
|
||||
if (srvSess.getMetaData("theSession") != null) {
|
||||
log.debug(srvSess);
|
||||
serverSessions.add(srvSess);
|
||||
}
|
||||
}
|
||||
latchFlag.countDown();
|
||||
|
||||
|
||||
latchFlag.countUp();
|
||||
latchEnter.countUp();
|
||||
latchEnter.countUp();
|
||||
|
||||
List<Thread> threads = new LinkedList<>();
|
||||
|
||||
threads.add(new Thread("ConsumerCloser") {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
log.debug(Thread.currentThread().getName() + " closing consumer");
|
||||
consumer.close();
|
||||
log.debug(Thread.currentThread().getName() + " closed consumer");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
threads.add(new Thread("SessionCloser") {
|
||||
@Override
|
||||
public void run() {
|
||||
for (ServerSession sess : serverSessions) {
|
||||
log.debug("Thread " + Thread.currentThread().getName() + " starting");
|
||||
try {
|
||||
// A session.close could sneak in through failover or some other scenarios.
|
||||
// a call to RemotingConnection.fail wasn't replicating the issue.
|
||||
// I needed to call Session.close() directly to replicate what was happening in production
|
||||
sess.close(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
log.debug("Thread " + Thread.currentThread().getName() + " done");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (Thread t : threads) {
|
||||
t.start();
|
||||
}
|
||||
|
||||
latchEnter.await(1, TimeUnit.SECONDS);
|
||||
latchFlag.countDown();
|
||||
|
||||
for (Thread t : threads) {
|
||||
t.join(5000);
|
||||
Assert.assertFalse(t.isAlive());
|
||||
}
|
||||
|
||||
connection.close();
|
||||
}
|
||||
|
||||
Connection connection = cf.createConnection();
|
||||
try {
|
||||
connection.setClientID("myID");
|
||||
|
||||
Thread.sleep(5000); // I am too lazy to call end on all the transactions
|
||||
connection.start();
|
||||
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageConsumer consumer = session.createConsumer(queue);
|
||||
HashMap<Integer, AtomicInteger> mapCount = new HashMap<>();
|
||||
|
||||
while (true) {
|
||||
TextMessage message = (TextMessage) consumer.receiveNoWait();
|
||||
if (message == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
Integer value = message.getIntProperty("i");
|
||||
|
||||
AtomicInteger count = mapCount.get(value);
|
||||
if (count == null) {
|
||||
count = new AtomicInteger(0);
|
||||
mapCount.put(message.getIntProperty("i"), count);
|
||||
}
|
||||
|
||||
count.incrementAndGet();
|
||||
}
|
||||
|
||||
boolean failed = false;
|
||||
for (int i = 0; i < numberOfMessages; i++) {
|
||||
AtomicInteger count = mapCount.get(i);
|
||||
if (count == null) {
|
||||
log.debug("Message " + i + " not received");
|
||||
failed = true;
|
||||
} else if (count.get() > 1) {
|
||||
log.debug("Message " + i + " received " + count.get() + " times");
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertFalse("test failed, look at the system.out of the test for more information", failed);
|
||||
} finally {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.DeliveryMode;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.server.JournalType;
|
||||
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
|
||||
import org.apache.activemq.artemis.tests.util.JMSTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.Wait;
|
||||
import org.apache.activemq.artemis.utils.critical.CriticalAnalyzerPolicy;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class CriticalAnalyzerFaultInjectionTest extends JMSTestBase {
|
||||
|
||||
// Critical Analyzer Settings
|
||||
private static long CHECK_PERIOD = 100;
|
||||
private static long TIMEOUT = 1000;
|
||||
public static long TEST_TIMEOUT = 5000;
|
||||
|
||||
private SimpleString address = SimpleString.toSimpleString("faultInjectionTestAddress");
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
server.addAddressInfo(new AddressInfo(address, RoutingType.ANYCAST));
|
||||
server.createQueue(new QueueConfiguration(address).setRoutingType(RoutingType.ANYCAST));
|
||||
conn = nettyCf.createConnection();
|
||||
}
|
||||
|
||||
/*
|
||||
Checks every 100ms timesout after 3000ms. Test should wait no longer than 3100s + Shutdown time.
|
||||
*/
|
||||
@Override
|
||||
protected Configuration createDefaultConfig(boolean netty) throws Exception {
|
||||
return super.createDefaultConfig(netty)
|
||||
.setCriticalAnalyzerPolicy(CriticalAnalyzerPolicy.SHUTDOWN)
|
||||
.setCriticalAnalyzer(true)
|
||||
.setCriticalAnalyzerCheckPeriod(CHECK_PERIOD)
|
||||
.setCriticalAnalyzerTimeout(TIMEOUT)
|
||||
.setJournalType(JournalType.NIO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usePersistence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Sync file data hangs",
|
||||
targetClass = "org.apache.activemq.artemis.core.io.nio.NIOSequentialFile",
|
||||
targetMethod = "sync",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.CriticalAnalyzerFaultInjectionTest.methodHang();")})
|
||||
@Test(timeout = 60000)
|
||||
public void testSlowDiskSync() throws Exception {
|
||||
sendConsumeDurableMessage();
|
||||
Wait.waitFor(() -> !server.isStarted(), WAIT_TIMEOUT * 5);
|
||||
assertFalse(server.isStarted());
|
||||
}
|
||||
|
||||
private void sendConsumeDurableMessage() throws Exception {
|
||||
try {
|
||||
Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
Queue jmsQueue = s.createQueue(address.toString());
|
||||
MessageProducer p = s.createProducer(jmsQueue);
|
||||
p.setDeliveryMode(DeliveryMode.PERSISTENT);
|
||||
conn.start();
|
||||
p.send(s.createTextMessage("payload"));
|
||||
} catch (JMSException expected) {
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void methodHang() throws InterruptedException {
|
||||
Thread.sleep(TEST_TIMEOUT);
|
||||
}
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p/>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.JMSTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ExceptionListener;
|
||||
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 java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class DisconnectOnCriticalFailureTest extends JMSTestBase {
|
||||
|
||||
private static AtomicBoolean corruptPacket = new AtomicBoolean(false);
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
corruptPacket.set(false);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Corrupt Decoding",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.PacketDecoder",
|
||||
targetMethod = "decode(byte)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.DisconnectOnCriticalFailureTest.doThrow();")})
|
||||
public void testSendDisconnect() throws Exception {
|
||||
createQueue("queue1");
|
||||
final Connection producerConnection = nettyCf.createConnection();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
try {
|
||||
producerConnection.setExceptionListener(new ExceptionListener() {
|
||||
@Override
|
||||
public void onException(JMSException e) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
corruptPacket.set(true);
|
||||
producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
} finally {
|
||||
corruptPacket.set(false);
|
||||
|
||||
if (producerConnection != null) {
|
||||
producerConnection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Corrupt Decoding",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.ClientPacketDecoder",
|
||||
targetMethod = "decode(org.apache.activemq.artemis.api.core.ActiveMQBuffer)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.DisconnectOnCriticalFailureTest.doThrow($1);")})
|
||||
public void testClientDisconnect() throws Exception {
|
||||
Queue q1 = createQueue("queue1");
|
||||
final Connection connection = nettyCf.createConnection();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
try {
|
||||
connection.setExceptionListener(new ExceptionListener() {
|
||||
@Override
|
||||
public void onException(JMSException e) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
MessageProducer producer = session.createProducer(q1);
|
||||
TextMessage m = session.createTextMessage("hello");
|
||||
producer.send(m);
|
||||
connection.start();
|
||||
|
||||
corruptPacket.set(true);
|
||||
MessageConsumer consumer = session.createConsumer(q1);
|
||||
consumer.receive(2000);
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
} finally {
|
||||
corruptPacket.set(false);
|
||||
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 60000)
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Corrupt Decoding",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.ClientPacketDecoder",
|
||||
targetMethod = "decode(org.apache.activemq.artemis.api.core.ActiveMQBuffer)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.DisconnectOnCriticalFailureTest.doThrow($1);")})
|
||||
public void testClientDisconnectLarge() throws Exception {
|
||||
Queue q1 = createQueue("queue1");
|
||||
final Connection connection = nettyCf.createConnection();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ServerLocator locator = ((ActiveMQConnectionFactory)nettyCf).getServerLocator();
|
||||
int minSize = locator.getMinLargeMessageSize();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < minSize; i++) {
|
||||
builder.append("a");
|
||||
}
|
||||
|
||||
try {
|
||||
connection.setExceptionListener(new ExceptionListener() {
|
||||
@Override
|
||||
public void onException(JMSException e) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
MessageProducer producer = session.createProducer(q1);
|
||||
TextMessage m = session.createTextMessage(builder.toString());
|
||||
producer.send(m);
|
||||
connection.start();
|
||||
|
||||
corruptPacket.set(true);
|
||||
MessageConsumer consumer = session.createConsumer(q1);
|
||||
Message lm = consumer.receive(2000);
|
||||
|
||||
//first receive won't crash because the packet
|
||||
//is SESS_RECEIVE_LARGE_MSG
|
||||
assertNotNull(lm);
|
||||
|
||||
//second receive will force server to send a
|
||||
//"forced delivery" message, and will cause
|
||||
//the exception to be thrown.
|
||||
lm = consumer.receive(5000);
|
||||
assertNull(lm);
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
} finally {
|
||||
corruptPacket.set(false);
|
||||
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void doThrow(ActiveMQBuffer buff) {
|
||||
byte type = buff.getByte(buff.readerIndex());
|
||||
if (corruptPacket.get() && type == PacketImpl.SESS_RECEIVE_MSG) {
|
||||
corruptPacket.set(false);
|
||||
throw new IllegalArgumentException("Invalid type: -84");
|
||||
}
|
||||
}
|
||||
|
||||
public static void doThrow() {
|
||||
if (corruptPacket.get()) {
|
||||
corruptPacket.set(false);
|
||||
throw new IllegalArgumentException("Invalid type: -84");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
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.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class FailureXATest extends ActiveMQTestBase {
|
||||
|
||||
protected ActiveMQServer server = null;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
server = createServer(createDefaultNettyConfig());
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Crash after onephase committed",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerSessionImpl",
|
||||
targetMethod = "xaCommit(javax.transaction.xa.Xid, boolean)",
|
||||
targetLocation = "EXIT",
|
||||
action = "throw new RuntimeException()")})
|
||||
public void testCrashServerAfterOnePhaseCommit() throws Exception {
|
||||
doTestCrashServerAfterXACommit(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Crash after onephase committed",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerSessionImpl",
|
||||
targetMethod = "xaCommit(javax.transaction.xa.Xid, boolean)",
|
||||
targetLocation = "EXIT",
|
||||
//helper = "org.apache.activemq.artemis.tests.extras.byteman.FailureXATest",
|
||||
action = "throw new RuntimeException()")})
|
||||
public void testCrashServerAfterTwoPhaseCommit() throws Exception {
|
||||
doTestCrashServerAfterXACommit(false);
|
||||
}
|
||||
|
||||
private void doTestCrashServerAfterXACommit(boolean onePhase) throws Exception {
|
||||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
|
||||
XAConnection connection = connectionFactory.createXAConnection();
|
||||
|
||||
try {
|
||||
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
|
||||
Queue queue = session.createQueue("Queue1");
|
||||
final XASession xaSession = connection.createXASession();
|
||||
MessageConsumer consumer = xaSession.createConsumer(queue);
|
||||
|
||||
MessageProducer producer = session.createProducer(queue);
|
||||
producer.send(session.createTextMessage("hello " + 1));
|
||||
session.commit();
|
||||
|
||||
XAResource xaResource = xaSession.getXAResource();
|
||||
final Xid xid = newXID();
|
||||
xaResource.start(xid, XAResource.TMNOFLAGS);
|
||||
|
||||
connection.start();
|
||||
Assert.assertNotNull(consumer.receive(5000));
|
||||
|
||||
xaResource.end(xid, XAResource.TMSUCCESS);
|
||||
|
||||
try {
|
||||
xaResource.commit(xid, onePhase);
|
||||
Assert.fail("didn't get expected exception!");
|
||||
} catch (XAException xae) {
|
||||
if (onePhase) {
|
||||
//expected error code is XAER_RMFAIL
|
||||
Assert.assertEquals(XAException.XAER_RMFAIL, xae.errorCode);
|
||||
} else {
|
||||
//expected error code is XA_RETRY
|
||||
Assert.assertEquals(XAException.XA_RETRY, xae.errorCode);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
import org.apache.activemq.artemis.core.server.ActivateCallback;
|
||||
import org.apache.activemq.artemis.core.server.NodeManager;
|
||||
import org.apache.activemq.artemis.core.server.NodeManager.LockListener;
|
||||
import org.apache.activemq.artemis.core.server.impl.FileLockNodeManager;
|
||||
import org.apache.activemq.artemis.utils.Wait;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class FileLockMonitorTest {
|
||||
|
||||
private File sharedDir;
|
||||
private volatile boolean lostLock = false;
|
||||
private volatile FileLockNodeManager nodeManager;
|
||||
private ScheduledThreadPoolExecutor executor;
|
||||
|
||||
@Before
|
||||
public void handleLockFile() throws Exception {
|
||||
sharedDir = File.createTempFile("shared-dir", "");
|
||||
sharedDir.delete();
|
||||
Assert.assertTrue(sharedDir.mkdir());
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "lock is invalid", targetClass = "org.apache.activemq.artemis.core.server.impl.FileLockNodeManager", targetMethod = "isLiveLockLost", action = "return true;") })
|
||||
public void testLockMonitorInvalid() throws Exception {
|
||||
lostLock = false;
|
||||
startServer();
|
||||
Wait.assertTrue("The FileLockNodeManager should have lost the lock", () -> lostLock, 20_000, 100);
|
||||
nodeManager.isStarted();
|
||||
nodeManager.crashLiveServer();
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
public static void throwNodeManagerException(String msg) {
|
||||
throw new NodeManager.NodeManagerException(msg);
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "lock is invalid", targetClass = "org.apache.activemq.artemis.core.server.impl.FileLockNodeManager",
|
||||
targetMethod = "getState",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.FileLockMonitorTest.throwNodeManagerException(\"EFS is disconnected\");") })
|
||||
public void testLockMonitorIOException() throws Exception {
|
||||
lostLock = false;
|
||||
startServer();
|
||||
Wait.assertTrue("The FileLockNodeManager should have lost the lock", () -> lostLock, 5000, 100);
|
||||
nodeManager.crashLiveServer();
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockMonitorHasCorrectLockAndState() throws Exception {
|
||||
lostLock = false;
|
||||
startServer();
|
||||
Assert.assertFalse("The FileLockNodeManager should not have lost the lock", Wait.waitFor(() -> lostLock, 5000, 100));
|
||||
nodeManager.crashLiveServer();
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "lock is invalid", targetClass = "org.apache.activemq.artemis.core.server.impl.FileLockNodeManager", targetMethod = "getState", action = "return 70;") })
|
||||
public void testLockMonitorHasLockWrongState() throws Exception {
|
||||
lostLock = false;
|
||||
startServer();
|
||||
Assert.assertFalse("The FileLockNodeManager should not have lost the lock", Wait.waitFor(() -> lostLock, 5000, 100));
|
||||
nodeManager.crashLiveServer();
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
public LockListener startServer() throws Exception {
|
||||
executor = new ScheduledThreadPoolExecutor(2);
|
||||
nodeManager = new FileLockNodeManager(sharedDir, false, executor);
|
||||
LockListener listener = () -> {
|
||||
lostLock = true;
|
||||
try {
|
||||
nodeManager.crashLiveServer();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
};
|
||||
nodeManager.registerLockListener(listener);
|
||||
|
||||
try {
|
||||
nodeManager.start();
|
||||
ActivateCallback startLiveNode = nodeManager.startLiveNode();
|
||||
startLiveNode.activationComplete();
|
||||
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
return listener;
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
import org.apache.activemq.artemis.core.server.impl.FileLockNodeManager;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class FileLockNodeManagerTest {
|
||||
private static final Logger log = Logger.getLogger(FileLockNodeManagerTest.class);
|
||||
|
||||
private static final int TIMEOUT_TOLERANCE = 50;
|
||||
|
||||
private File sharedDir;
|
||||
|
||||
public FileLockNodeManagerTest() throws IOException {
|
||||
sharedDir = File.createTempFile("shared-dir", "");
|
||||
sharedDir.delete();
|
||||
Assert.assertTrue(sharedDir.mkdir());
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "throw IOException during activation",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.FileLockNodeManager",
|
||||
targetMethod = "tryLock",
|
||||
targetLocation = "AT ENTRY",
|
||||
action = "THROW new IOException(\"IO Error\");")
|
||||
})
|
||||
public void test() throws Exception {
|
||||
measureLockAcquisisionTimeout(100); // warm-up
|
||||
|
||||
assertMeasuredTimeoutFor(100);
|
||||
assertMeasuredTimeoutFor(200);
|
||||
}
|
||||
|
||||
protected void assertMeasuredTimeoutFor(long lockAcquisitionTimeout) throws Exception {
|
||||
long realTimeout = measureLockAcquisisionTimeout(lockAcquisitionTimeout);
|
||||
log.debug(String.format("lockAcquisisionTimeout: %d ms, measured timeout: %d ms", lockAcquisitionTimeout, realTimeout));
|
||||
Assert.assertTrue(String.format("Timeout %d ms was larger than expected %d ms", realTimeout, lockAcquisitionTimeout + TIMEOUT_TOLERANCE),
|
||||
lockAcquisitionTimeout + TIMEOUT_TOLERANCE >= realTimeout);
|
||||
Assert.assertTrue(String.format("Timeout %d ms was lower than expected %d ms", realTimeout, lockAcquisitionTimeout),
|
||||
lockAcquisitionTimeout + TIMEOUT_TOLERANCE >= realTimeout);
|
||||
}
|
||||
|
||||
private long measureLockAcquisisionTimeout(long lockAcquisitionTimeout) throws Exception {
|
||||
FileLockNodeManager manager = new FileLockNodeManager(sharedDir, false, lockAcquisitionTimeout, new ScheduledThreadPoolExecutor(1));
|
||||
manager.start();
|
||||
|
||||
// try to lock and measure real timeout
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
manager.awaitLiveNode();
|
||||
} catch (Exception e) {
|
||||
long stop = System.currentTimeMillis();
|
||||
if (!"timed out waiting for lock".equals(e.getCause().getMessage())) {
|
||||
throw e;
|
||||
}
|
||||
return stop - start;
|
||||
}
|
||||
Assert.fail("Exception expected");
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionFactory;
|
||||
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 org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||
import org.apache.activemq.artemis.tests.util.JMSTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* GroupingTest
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class GroupingTest extends JMSTestBase {
|
||||
private static final Logger log = Logger.getLogger(GroupingTest.class);
|
||||
|
||||
private Queue queue;
|
||||
static boolean pause = false;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
queue = createQueue("TestQueue");
|
||||
}
|
||||
|
||||
protected ConnectionFactory getCF() throws Exception {
|
||||
return cf;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "trace clientsessionimpl commit",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerSessionImpl",
|
||||
targetMethod = "rollback",
|
||||
targetLocation = "EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.GroupingTest.pause();")})
|
||||
public void testGroupingRollbackOnClose() throws Exception {
|
||||
Connection sendConnection = null;
|
||||
Connection connection = null;
|
||||
Connection connection2 = null;
|
||||
try {
|
||||
ActiveMQConnectionFactory fact = (ActiveMQConnectionFactory) getCF();
|
||||
fact.setReconnectAttempts(0);
|
||||
//fact.setConsumerWindowSize(1000);
|
||||
//fact.setTransactionBatchSize(0);
|
||||
connection = fact.createConnection();
|
||||
RemotingConnection rc = server.getRemotingService().getConnections().iterator().next();
|
||||
connection2 = fact.createConnection();
|
||||
sendConnection = fact.createConnection();
|
||||
|
||||
final Session sendSession = sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
|
||||
Session session2 = connection2.createSession(true, Session.SESSION_TRANSACTED);
|
||||
|
||||
final MessageProducer producer = sendSession.createProducer(queue);
|
||||
|
||||
MessageConsumer consumer1 = session.createConsumer(queue);
|
||||
MessageConsumer consumer2 = session2.createConsumer(queue);
|
||||
|
||||
connection.start();
|
||||
connection2.start();
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
for (int j = 0; j < 10000; j++) {
|
||||
TextMessage message = sendSession.createTextMessage();
|
||||
|
||||
message.setText("Message" + j);
|
||||
|
||||
message.setStringProperty("JMSXGroupID", "foo");
|
||||
|
||||
producer.send(message);
|
||||
}
|
||||
} catch (JMSException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
//consume 5 msgs from 1st first consumer
|
||||
for (int j = 0; j < 5; j++) {
|
||||
TextMessage tm = (TextMessage) consumer1.receive(10000);
|
||||
|
||||
assertNotNull(tm);
|
||||
|
||||
assertEquals("Message" + j, tm.getText());
|
||||
|
||||
assertEquals(tm.getStringProperty("JMSXGroupID"), "foo");
|
||||
}
|
||||
|
||||
pause = true;
|
||||
rc.fail(new ActiveMQNotConnectedException());
|
||||
pause = false;
|
||||
|
||||
for (int j = 0; j < 10000; j++) {
|
||||
TextMessage tm = (TextMessage) consumer2.receive(5000);
|
||||
|
||||
assertNotNull(tm);
|
||||
|
||||
assertEquals("Message" + j, tm.getText());
|
||||
|
||||
assertEquals(tm.getStringProperty("JMSXGroupID"), "foo");
|
||||
}
|
||||
} finally {
|
||||
if (sendConnection != null) {
|
||||
sendConnection.close();
|
||||
}
|
||||
if (connection2 != null) {
|
||||
connection2.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void pause() {
|
||||
if (pause) {
|
||||
try {
|
||||
log.debug("pausing after rollback");
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
|
||||
}
|
||||
log.debug("finished pausing after rollback");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.core.settings.impl.HierarchicalObjectRepository;
|
||||
import org.apache.activemq.artemis.utils.ActiveMQThreadFactory;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "modify map during iteration",
|
||||
targetClass = "org.apache.activemq.artemis.core.settings.impl.HierarchicalObjectRepository",
|
||||
targetMethod = "getPossibleMatches(String)",
|
||||
targetLocation = "AT INVOKE java.util.HashMap.put",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.HierarchicalObjectRepositoryTest.bum()"),})
|
||||
public class HierarchicalObjectRepositoryTest {
|
||||
|
||||
private static final String A = "a.";
|
||||
private static final int TOTAL = 100;
|
||||
private static CountDownLatch latch;
|
||||
private static CountDownLatch latch2;
|
||||
private ExecutorService executor;
|
||||
private HierarchicalObjectRepository<String> repo;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
latch = new CountDownLatch(1);
|
||||
latch2 = new CountDownLatch(1);
|
||||
executor = Executors.newSingleThreadExecutor(ActiveMQThreadFactory.defaultThreadFactory(getClass().getName()));
|
||||
repo = new HierarchicalObjectRepository<>();
|
||||
addToRepo(repo, A);
|
||||
}
|
||||
|
||||
static void addToRepo(HierarchicalObjectRepository<String> repo0, String pattern) {
|
||||
for (int i = 0; i < TOTAL; i++) {
|
||||
repo0.addMatch(pattern + i + ".*", String.valueOf(i));
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws InterruptedException {
|
||||
latch.countDown();
|
||||
latch2.countDown();
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private class Clearer implements Runnable {
|
||||
|
||||
private final int code;
|
||||
|
||||
private Clearer(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 0:
|
||||
repo.clear();
|
||||
break;
|
||||
case 1:
|
||||
addToRepo(repo, "bb.");
|
||||
break;
|
||||
case 2:
|
||||
for (int i = TOTAL / 2; i < TOTAL; i++) {
|
||||
repo.removeMatch(A + i + ".*");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
latch2.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentModificationsClear() {
|
||||
executor.execute(new Clearer(0));
|
||||
repo.getMatch(A + (TOTAL - 10) + ".foobar");
|
||||
Assert.assertEquals("Byteman rule failed?", 0, latch.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentModificationsAdd() {
|
||||
executor.execute(new Clearer(1));
|
||||
repo.getMatch(A + (TOTAL - 10) + ".foobar");
|
||||
Assert.assertEquals("Byteman rule failed?", 0, latch.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentModificationsRemove() {
|
||||
executor.execute(new Clearer(2));
|
||||
repo.getMatch(A + (TOTAL - 10) + ".foobar");
|
||||
Assert.assertEquals("Byteman rule failed?", 0, latch.getCount());
|
||||
}
|
||||
|
||||
public static void bum() {
|
||||
latch.countDown();
|
||||
try {
|
||||
latch2.await(3, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// no op
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Message;
|
||||
import javax.resource.ResourceException;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAException;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import javax.transaction.xa.Xid;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.arjuna.ats.arjuna.coordinator.TransactionReaper;
|
||||
import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome;
|
||||
import com.arjuna.ats.arjuna.coordinator.TxControl;
|
||||
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.ra.ActiveMQResourceAdapter;
|
||||
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivationSpec;
|
||||
import org.apache.activemq.artemis.tests.integration.ra.ActiveMQRATestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class InterruptedMessageHandlerTest extends ActiveMQRATestBase {
|
||||
|
||||
@Override
|
||||
protected boolean usePersistence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSecurity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "throw ActiveMQException(CONNETION_TIMEOUT) during rollback",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientSessionImpl",
|
||||
targetMethod = "flushAcks",
|
||||
targetLocation = "AFTER INVOKE flushAcks",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.InterruptedMessageHandlerTest.throwActiveMQQExceptionConnectionTimeout();"),
|
||||
@BMRule(
|
||||
name = "check that outcome of XA transaction is TwoPhaseOutcome.FINISH_ERROR=8",
|
||||
targetClass = "com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord",
|
||||
targetMethod = "topLevelAbort",
|
||||
targetLocation = "AT EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.InterruptedMessageHandlerTest.assertTxOutComeIsOfStatusFinishedError($!);")})
|
||||
public void testSimpleMessageReceivedOnQueueTwoPhaseFailPrepareByConnectionTimout() throws Exception {
|
||||
ActiveMQResourceAdapter qResourceAdapter = newResourceAdapter();
|
||||
resourceAdapter = qResourceAdapter;
|
||||
|
||||
MyBootstrapContext ctx = new MyBootstrapContext();
|
||||
|
||||
qResourceAdapter.setConnectorClassName(NETTY_CONNECTOR_FACTORY);
|
||||
qResourceAdapter.start(ctx);
|
||||
|
||||
ActiveMQActivationSpec spec = new ActiveMQActivationSpec();
|
||||
spec.setMaxSession(1);
|
||||
spec.setCallTimeout(1000L);
|
||||
spec.setResourceAdapter(qResourceAdapter);
|
||||
spec.setUseJNDI(false);
|
||||
spec.setDestinationType("javax.jms.Queue");
|
||||
spec.setDestination(MDBQUEUE);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
XADummyEndpointWithDummyXAResourceFailEnd endpoint = new XADummyEndpointWithDummyXAResourceFailEnd(latch, true);
|
||||
|
||||
DummyMessageEndpointFactory endpointFactory = new DummyMessageEndpointFactory(endpoint, true);
|
||||
|
||||
qResourceAdapter.endpointActivation(endpointFactory, spec);
|
||||
|
||||
ClientSession session = locator.createSessionFactory().createSession();
|
||||
|
||||
ClientProducer clientProducer = session.createProducer(MDBQUEUEPREFIXED);
|
||||
|
||||
ClientMessage message = session.createMessage(true);
|
||||
|
||||
message.getBodyBuffer().writeString("teststring");
|
||||
|
||||
clientProducer.send(message);
|
||||
|
||||
session.close();
|
||||
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
assertNotNull(endpoint.lastMessage);
|
||||
assertEquals(endpoint.lastMessage.getCoreMessage().getBodyBuffer().readString(), "teststring");
|
||||
|
||||
qResourceAdapter.endpointDeactivation(endpointFactory, spec);
|
||||
|
||||
qResourceAdapter.stop();
|
||||
|
||||
server.stop();
|
||||
|
||||
assertEquals("Two phase outcome must be of TwoPhaseOutcome.FINISH_ERROR.", TwoPhaseOutcome.FINISH_ERROR, txTwoPhaseOutCome.intValue());
|
||||
|
||||
}
|
||||
|
||||
static volatile ActiveMQResourceAdapter resourceAdapter;
|
||||
static boolean resourceAdapterStopped = false;
|
||||
|
||||
public static void interrupt() throws InterruptedException {
|
||||
if (!resourceAdapterStopped) {
|
||||
resourceAdapter.stop();
|
||||
resourceAdapterStopped = true;
|
||||
throw new InterruptedException("foo");
|
||||
}
|
||||
}
|
||||
|
||||
public static void throwActiveMQQExceptionConnectionTimeout() throws ActiveMQException, XAException {
|
||||
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
|
||||
for (StackTraceElement element : stackTraceElements) {
|
||||
if (element.getClassName().contains("ClientSessionImpl") && element.getMethodName().contains("rollback")) {
|
||||
throw new ActiveMQException(ActiveMQExceptionType.CONNECTION_TIMEDOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Integer txTwoPhaseOutCome = null;
|
||||
|
||||
public static void assertTxOutComeIsOfStatusFinishedError(int txOutCome) {
|
||||
// check only first trigger of byteman rule
|
||||
if (txTwoPhaseOutCome == null) {
|
||||
txTwoPhaseOutCome = Integer.valueOf(txOutCome);
|
||||
}
|
||||
}
|
||||
|
||||
Transaction currentTX;
|
||||
|
||||
public class XADummyEndpoint extends DummyMessageEndpoint {
|
||||
|
||||
final boolean twoPhase;
|
||||
ClientSession session;
|
||||
int afterDeliveryCounts = 0;
|
||||
|
||||
public XADummyEndpoint(CountDownLatch latch, boolean twoPhase) throws SystemException {
|
||||
super(latch);
|
||||
this.twoPhase = twoPhase;
|
||||
try {
|
||||
session = locator.createSessionFactory().createSession(true, false, false);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDelivery(Method method) throws NoSuchMethodException, ResourceException {
|
||||
super.beforeDelivery(method);
|
||||
try {
|
||||
DummyTMLocator.tm.begin();
|
||||
currentTX = DummyTMLocator.tm.getTransaction();
|
||||
currentTX.enlistResource(xaResource);
|
||||
if (twoPhase) {
|
||||
currentTX.enlistResource(new DummyXAResource());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message) {
|
||||
super.onMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDelivery() throws ResourceException {
|
||||
afterDeliveryCounts++;
|
||||
try {
|
||||
currentTX.commit();
|
||||
} catch (Throwable e) {
|
||||
// its unsure as to whether the EJB/JCA layer will handle this or throw it to us,
|
||||
// either way we don't do anything else so its fine just to throw.
|
||||
// NB this will only happen with 2 phase commit
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
super.afterDelivery();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
resourceAdapter = null;
|
||||
resourceAdapterStopped = false;
|
||||
super.setUp();
|
||||
DummyTMLocator.startTM();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
DummyTMLocator.stopTM();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public static class DummyTMLocator {
|
||||
|
||||
public static TransactionManagerImple tm;
|
||||
|
||||
public static void stopTM() {
|
||||
try {
|
||||
TransactionReaper.terminate(true);
|
||||
TxControl.disable(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
tm = null;
|
||||
}
|
||||
|
||||
public static void startTM() {
|
||||
tm = new TransactionManagerImple();
|
||||
TxControl.enable();
|
||||
}
|
||||
|
||||
public TransactionManager getTM() {
|
||||
return tm;
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyXAResource implements XAResource {
|
||||
|
||||
@Override
|
||||
public void commit(Xid xid, boolean b) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(Xid xid, int i) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forget(Xid xid) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransactionTimeout() throws XAException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameRM(XAResource xaResource) throws XAException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prepare(Xid xid) throws XAException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Xid[] recover(int i) throws XAException {
|
||||
return new Xid[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(Xid xid) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTransactionTimeout(int i) throws XAException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Xid xid, int i) throws XAException {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class XADummyEndpointWithDummyXAResourceFailEnd extends XADummyEndpoint {
|
||||
|
||||
public XADummyEndpointWithDummyXAResourceFailEnd(CountDownLatch latch, boolean twoPhase) throws SystemException {
|
||||
super(latch, twoPhase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDelivery(Method method) throws NoSuchMethodException, ResourceException {
|
||||
try {
|
||||
DummyTMLocator.tm.begin();
|
||||
currentTX = DummyTMLocator.tm.getTransaction();
|
||||
currentTX.enlistResource(xaResource);
|
||||
if (twoPhase) {
|
||||
currentTX.enlistResource(new DummyXAResourceFailEnd());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DummyXAResourceFailEnd extends DummyXAResource {
|
||||
|
||||
@Override
|
||||
public void end(Xid xid, int i) throws XAException {
|
||||
throw new XAException(XAException.XAER_RMFAIL);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.Message;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientProducerCredits;
|
||||
import org.apache.activemq.artemis.core.protocol.core.Packet;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionSendMessage;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory;
|
||||
import org.apache.activemq.artemis.jms.bridge.QualityOfServiceMode;
|
||||
import org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl;
|
||||
import org.apache.activemq.artemis.tests.extras.jms.bridge.BridgeTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class JMSBridgeReconnectionTest extends BridgeTestBase {
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "trace clientsessionimpl send",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl",
|
||||
targetMethod = "send",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.JMSBridgeReconnectionTest.pause($1);"),
|
||||
@BMRule(
|
||||
name = "trace sendRegularMessage",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientProducerImpl",
|
||||
targetMethod = "sendRegularMessage",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.JMSBridgeReconnectionTest.pause2($2,$3,$4);")})
|
||||
public void performCrashDestinationStopBridge() throws Exception {
|
||||
activeMQServer = server1;
|
||||
ConnectionFactoryFactory factInUse0 = cff0;
|
||||
ConnectionFactoryFactory factInUse1 = cff1;
|
||||
final JMSBridgeImpl bridge = new JMSBridgeImpl(factInUse0, factInUse1, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, QualityOfServiceMode.DUPLICATES_OK, 10, -1, null, null, false).setBridgeName("test-bridge");
|
||||
|
||||
addActiveMQComponent(bridge);
|
||||
bridge.setTransactionManager(newTransactionManager());
|
||||
bridge.start();
|
||||
final CountDownLatch latch = new CountDownLatch(20);
|
||||
Thread clientThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (bridge.isStarted()) {
|
||||
try {
|
||||
sendMessages(cf0, sourceQueue, 0, 1, false, false);
|
||||
latch.countDown();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
clientThread.start();
|
||||
|
||||
stopLatch.await(10000, TimeUnit.MILLISECONDS);
|
||||
|
||||
bridge.stop();
|
||||
|
||||
clientThread.join(5000);
|
||||
|
||||
assertTrue(!clientThread.isAlive());
|
||||
}
|
||||
|
||||
public static void pause(Packet packet) {
|
||||
if (packet.getType() == PacketImpl.SESS_SEND) {
|
||||
SessionSendMessage sendMessage = (SessionSendMessage) packet;
|
||||
if (sendMessage.getMessage().containsProperty("__AMQ_CID") && count < 0 && !stopped) {
|
||||
try {
|
||||
activeMQServer.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
stopped = true;
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
stopLatch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ActiveMQServer activeMQServer;
|
||||
static boolean stopped = false;
|
||||
static int count = 20;
|
||||
static CountDownLatch stopLatch = new CountDownLatch(1);
|
||||
|
||||
public static void pause2(Message msgI, boolean sendBlocking, final ClientProducerCredits theCredits) {
|
||||
if (msgI.containsProperty("__AMQ_CID")) {
|
||||
count--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import org.apache.activemq.artemis.core.io.SequentialFileFactory;
|
||||
import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestBase;
|
||||
import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class JournalImplConcurrencyTest extends JournalImplTestBase {
|
||||
|
||||
@Override
|
||||
protected SequentialFileFactory getFileFactory() {
|
||||
return new FakeSequentialFileFactory();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests that JournalImpl#checkKnownRecordID() doesn't hang when the executor thread fails with
|
||||
* an exception before setting the future value.
|
||||
*/
|
||||
@Test(timeout = 2000)
|
||||
@BMRules(rules = {
|
||||
@BMRule(
|
||||
name = "BlockOnFinalLargeMessagePacket",
|
||||
targetClass = "java.util.concurrent.locks.ReentrantReadWriteLock",
|
||||
targetMethod = "readLock()",
|
||||
targetLocation = "EXIT",
|
||||
condition = "Thread.currentThread().getName().contains(\"ArtemisIOThread\")",
|
||||
action = "throw RuntimeException(\"Injected exception\");")})
|
||||
public void testTryDelete() throws Exception {
|
||||
setup(10, 10 * 1024, true);
|
||||
createJournal();
|
||||
startJournal();
|
||||
load();
|
||||
addTx(1, 1, 2, 3);
|
||||
|
||||
try {
|
||||
tryDelete(1);
|
||||
Assert.fail("Expected to throw exception injected by a byteman rule");
|
||||
} catch (ExecutionException e) {
|
||||
Assert.assertTrue(e.getCause() instanceof RuntimeException);
|
||||
Assert.assertEquals("Injected exception", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
stopJournal();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffers;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.Wait;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class LargeMessageOnShutdownTest extends ActiveMQTestBase {
|
||||
|
||||
private static final SimpleString queueName = new SimpleString("largeMessageShutdownQueue");
|
||||
private static ActiveMQServer server;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
server = createServer(true, createDefaultNettyConfig());
|
||||
startServer();
|
||||
server.createQueue(new QueueConfiguration(queueName));
|
||||
}
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
stopServer();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "BlockOnFinalLargeMessagePacket",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerSessionImpl",
|
||||
targetMethod = "doSend(Transaction,Message,SimpleString,boolean,boolean)",
|
||||
targetLocation = "EXIT",
|
||||
condition = "!flagged(\"testLargeMessageOnShutdown\")",
|
||||
action =
|
||||
"org.apache.activemq.artemis.tests.extras.byteman.LargeMessageOnShutdownTest.stopServer();" +
|
||||
"waitFor(\"testLargeMessageOnShutdown\", 5000);" +
|
||||
"flag(\"testLargeMessageOnShutdown\")"),
|
||||
@BMRule(
|
||||
name = "ReleaseBlockOnSessionCleanup",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.ServerSessionPacketHandler",
|
||||
targetMethod = "clearLargeMessage()",
|
||||
targetLocation = "EXIT",
|
||||
action = "signalWake(\"testLargeMessageOnShutdown\")")
|
||||
}
|
||||
)
|
||||
public void testLargeMessageOnShutdown() throws Exception {
|
||||
|
||||
byte[] payload = new byte[ActiveMQClient.DEFAULT_MIN_LARGE_MESSAGE_SIZE * 2];
|
||||
|
||||
// Send Large Message
|
||||
ClientSessionFactory csf1 = createSessionFactory(createNettyNonHALocator());
|
||||
try {
|
||||
ClientSession session1 = csf1.createSession();
|
||||
ClientProducer producer1 = session1.createProducer(queueName);
|
||||
ClientMessage message = session1.createMessage(true);
|
||||
|
||||
message.setBodyInputStream(new ByteArrayInputStream(payload));
|
||||
producer1.send(message);
|
||||
} catch (Exception e) {
|
||||
// Expected due to shutdown.
|
||||
} finally {
|
||||
csf1.close();
|
||||
}
|
||||
|
||||
waitForStoppedServer();
|
||||
startServer();
|
||||
|
||||
// Consume Large Message
|
||||
ClientSessionFactory csf2 = createSessionFactory(createNettyNonHALocator());
|
||||
try {
|
||||
ClientSession session2 = csf2.createSession();
|
||||
session2.start();
|
||||
ClientConsumer consumer2 = session2.createConsumer(queueName);
|
||||
ClientMessage rmessage = consumer2.receive(10000);
|
||||
|
||||
assertEquals(payload.length, rmessage.getBodyBuffer().readableBytes());
|
||||
assertEqualsBuffers(payload.length, ActiveMQBuffers.wrappedBuffer(payload), rmessage.getBodyBuffer());
|
||||
} finally {
|
||||
csf2.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopServer() throws Exception {
|
||||
server.stop();
|
||||
waitForStoppedServer();
|
||||
}
|
||||
|
||||
public static void startServer() throws Exception {
|
||||
server.start();
|
||||
server.waitForActivation(30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public static void waitForStoppedServer() throws Exception {
|
||||
Wait.waitFor(() -> server.getState() == ActiveMQServer.SERVER_STATE.STOPPED);
|
||||
}
|
||||
}
|
|
@ -1,259 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MapMessage;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.CoreQueueConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnection;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.ReplicatedBackupUtils;
|
||||
import org.apache.activemq.artemis.tests.util.TransportConfigurationUtils;
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class LargeMessageOverReplicationTest extends ActiveMQTestBase {
|
||||
|
||||
public static int messageChunkCount = 0;
|
||||
|
||||
private static final ReusableLatch ruleFired = new ReusableLatch(1);
|
||||
private static ActiveMQServer backupServer;
|
||||
private static ActiveMQServer liveServer;
|
||||
|
||||
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616?minLargeMessageSize=10000&HA=true&retryInterval=100&reconnectAttempts=-1&producerWindowSize=10000");
|
||||
ActiveMQConnection connection;
|
||||
Session session;
|
||||
Queue queue;
|
||||
MessageProducer producer;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
ruleFired.setCount(1);
|
||||
messageChunkCount = 0;
|
||||
|
||||
TransportConfiguration liveConnector = TransportConfigurationUtils.getNettyConnector(true, 0);
|
||||
TransportConfiguration liveAcceptor = TransportConfigurationUtils.getNettyAcceptor(true, 0);
|
||||
TransportConfiguration backupConnector = TransportConfigurationUtils.getNettyConnector(false, 0);
|
||||
TransportConfiguration backupAcceptor = TransportConfigurationUtils.getNettyAcceptor(false, 0);
|
||||
|
||||
Configuration backupConfig = createDefaultInVMConfig().setBindingsDirectory(getBindingsDir(0, true)).setJournalDirectory(getJournalDir(0, true)).setPagingDirectory(getPageDir(0, true)).setLargeMessagesDirectory(getLargeMessagesDir(0, true));
|
||||
|
||||
Configuration liveConfig = createDefaultInVMConfig();
|
||||
|
||||
ReplicatedBackupUtils.configureReplicationPair(backupConfig, backupConnector, backupAcceptor, liveConfig, liveConnector, liveAcceptor);
|
||||
|
||||
liveServer = createServer(liveConfig);
|
||||
liveServer.getConfiguration().addQueueConfiguration(new CoreQueueConfiguration().setName("Queue").setAddress("Queue"));
|
||||
liveServer.start();
|
||||
|
||||
waitForServerToStart(liveServer);
|
||||
|
||||
backupServer = createServer(backupConfig);
|
||||
backupServer.start();
|
||||
|
||||
waitForServerToStart(backupServer);
|
||||
|
||||
// Just to make sure the expression worked
|
||||
Assert.assertEquals(10000, factory.getMinLargeMessageSize());
|
||||
Assert.assertEquals(10000, factory.getProducerWindowSize());
|
||||
Assert.assertEquals(100, factory.getRetryInterval());
|
||||
Assert.assertEquals(-1, factory.getReconnectAttempts());
|
||||
Assert.assertTrue(factory.isHA());
|
||||
|
||||
connection = (ActiveMQConnection) factory.createConnection();
|
||||
|
||||
waitForRemoteBackup(connection.getSessionFactory(), 30);
|
||||
|
||||
session = connection.createSession(true, Session.SESSION_TRANSACTED);
|
||||
queue = session.createQueue("Queue");
|
||||
producer = session.createProducer(queue);
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServers() throws Exception {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
if (backupServer != null) {
|
||||
backupServer.stop();
|
||||
backupServer = null;
|
||||
}
|
||||
|
||||
if (liveServer != null) {
|
||||
liveServer.stop();
|
||||
liveServer = null;
|
||||
}
|
||||
|
||||
backupServer = liveServer = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* simple test to induce a potential race condition where the server's acceptors are active, but the server's
|
||||
* state != STARTED
|
||||
*/
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "InterruptSending",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext",
|
||||
targetMethod = "sendLargeMessageChunk",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LargeMessageOverReplicationTest.messageChunkSent();")})
|
||||
public void testSendLargeMessage() throws Exception {
|
||||
|
||||
MapMessage message = createLargeMessage();
|
||||
|
||||
try {
|
||||
producer.send(message);
|
||||
Assert.fail("expected an exception");
|
||||
// session.commit();
|
||||
} catch (JMSException expected) {
|
||||
}
|
||||
|
||||
session.rollback();
|
||||
|
||||
producer.send(message);
|
||||
session.commit();
|
||||
|
||||
MessageConsumer consumer = session.createConsumer(queue);
|
||||
connection.start();
|
||||
|
||||
MapMessage messageRec = (MapMessage) consumer.receive(5000);
|
||||
Assert.assertNotNull(messageRec);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Assert.assertEquals(1024 * 1024, message.getBytes("test" + i).length);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "InterruptReceive",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.CoreSessionCallback",
|
||||
targetMethod = "sendLargeMessageContinuation",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LargeMessageOverReplicationTest.messageChunkReceived();")})
|
||||
public void testReceiveLargeMessage() throws Exception {
|
||||
|
||||
MapMessage message = createLargeMessage();
|
||||
|
||||
producer.send(message);
|
||||
session.commit();
|
||||
|
||||
MessageConsumer consumer = session.createConsumer(queue);
|
||||
connection.start();
|
||||
|
||||
MapMessage messageRec = null;
|
||||
|
||||
try {
|
||||
consumer.receive(5000);
|
||||
Assert.fail("Expected a failure here");
|
||||
} catch (JMSException expected) {
|
||||
}
|
||||
|
||||
session.rollback();
|
||||
|
||||
messageRec = (MapMessage) consumer.receive(5000);
|
||||
Assert.assertNotNull(messageRec);
|
||||
session.commit();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Assert.assertEquals(1024 * 1024, message.getBytes("test" + i).length);
|
||||
}
|
||||
}
|
||||
|
||||
public static void messageChunkReceived() {
|
||||
messageChunkCount++;
|
||||
|
||||
if (messageChunkCount == 100) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
latch.countDown();
|
||||
liveServer.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
try {
|
||||
// just to make sure it's about to be stopped
|
||||
// avoiding bootstrapping the thread as a delay
|
||||
latch.await(1, TimeUnit.MINUTES);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void messageChunkSent() {
|
||||
messageChunkCount++;
|
||||
|
||||
try {
|
||||
if (messageChunkCount == 10) {
|
||||
liveServer.fail(true);
|
||||
|
||||
System.err.println("activating");
|
||||
if (!backupServer.waitForActivation(1, TimeUnit.MINUTES)) {
|
||||
Logger.getLogger(LargeMessageOverReplicationTest.class).warn("Can't failover server");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private MapMessage createLargeMessage() throws JMSException {
|
||||
MapMessage message = session.createMapMessage();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
message.setBytes("test" + i, new byte[1024 * 1024]);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.DivertConfiguration;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||
import org.apache.activemq.artemis.tests.integration.cluster.failover.FailoverTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class LargeMessageReplicationTest extends FailoverTestBase {
|
||||
private static final Logger log = Logger.getLogger(LargeMessageReplicationTest.class);
|
||||
|
||||
private static final String DIVERT_ADDRESS = "jms.queue.testQueue";
|
||||
private static final String DIVERT_FORWARD_ADDRESS = "jms.queue.divertedQueue";
|
||||
private ClientSessionFactoryInternal sf;
|
||||
|
||||
private static AtomicLong copyThread = new AtomicLong(-1);
|
||||
private static List<byte[]> sourceBytes = new ArrayList<>();
|
||||
private static byte[] originalBuffer;
|
||||
private static boolean isOk;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
isOk = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransportConfiguration getAcceptorTransportConfiguration(final boolean live) {
|
||||
return getNettyAcceptorTransportConfiguration(live);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransportConfiguration getConnectorTransportConfiguration(final boolean live) {
|
||||
return getNettyConnectorTransportConfiguration(live);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createConfigs() throws Exception {
|
||||
createReplicatedConfigs();
|
||||
|
||||
liveConfig.setJournalFileSize(10240000);
|
||||
backupConfig.setJournalFileSize(10240000);
|
||||
addQueue(liveConfig, DIVERT_ADDRESS, DIVERT_ADDRESS);
|
||||
addQueue(liveConfig, DIVERT_FORWARD_ADDRESS, DIVERT_FORWARD_ADDRESS);
|
||||
addDivert(liveConfig, DIVERT_ADDRESS, DIVERT_FORWARD_ADDRESS, false);
|
||||
addDivert(backupConfig, DIVERT_ADDRESS, DIVERT_FORWARD_ADDRESS, false);
|
||||
}
|
||||
|
||||
private void addQueue(Configuration serverConfig, String address, String name) {
|
||||
|
||||
List<CoreAddressConfiguration> addrConfigs = serverConfig.getAddressConfigurations();
|
||||
CoreAddressConfiguration addrCfg = new CoreAddressConfiguration();
|
||||
addrCfg.setName(address);
|
||||
addrCfg.addRoutingType(RoutingType.ANYCAST);
|
||||
addrCfg.addQueueConfiguration(new QueueConfiguration(name).setAddress(address));
|
||||
addrConfigs.add(addrCfg);
|
||||
}
|
||||
|
||||
private void addDivert(Configuration serverConfig, String source, String target, boolean exclusive) {
|
||||
List<DivertConfiguration> divertConfigs = serverConfig.getDivertConfigurations();
|
||||
DivertConfiguration newDivert = new DivertConfiguration();
|
||||
newDivert.setName("myDivert");
|
||||
newDivert.setAddress(source);
|
||||
newDivert.setForwardingAddress(target);
|
||||
newDivert.setExclusive(exclusive);
|
||||
divertConfigs.add(newDivert);
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "record large message copy thread",
|
||||
targetClass = "org.apache.activemq.artemis.core.persistence.impl.journal.LargeServerMessageImpl",
|
||||
targetMethod = "copy(long)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LargeMessageReplicationTest.copyThread()"),
|
||||
@BMRule(
|
||||
name = "record byte array in addBytes",
|
||||
targetClass = "org.apache.activemq.artemis.core.persistence.impl.journal.LargeServerMessageImpl",
|
||||
targetMethod = "addBytes(byte[])",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LargeMessageReplicationTest.addBytesIn($1)"),
|
||||
@BMRule(
|
||||
name = "record byte array used for reading large message",
|
||||
targetClass = "^org.apache.activemq.artemis.core.io.SequentialFile",
|
||||
isInterface = true,
|
||||
targetMethod = "read(java.nio.ByteBuffer)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LargeMessageReplicationTest.originBuff($1)")})
|
||||
//https://issues.apache.org/jira/browse/ARTEMIS-1220
|
||||
public void testDivertCopyMessageBuffer() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(TransportConstants.HOST_PROP_NAME, "localhost");
|
||||
TransportConfiguration tc = createTransportConfiguration(true, false, params);
|
||||
ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithHA(tc)).setBlockOnNonDurableSend(true).setBlockOnDurableSend(true).setBlockOnAcknowledge(true).setReconnectAttempts(-1);
|
||||
sf = createSessionFactoryAndWaitForTopology(locator, 2);
|
||||
int minLarge = locator.getMinLargeMessageSize();
|
||||
|
||||
ClientSession session = sf.createSession(false, false);
|
||||
addClientSession(session);
|
||||
session.start();
|
||||
|
||||
ClientProducer producer = session.createProducer(DIVERT_ADDRESS);
|
||||
ClientMessage message = createLargeMessage(session, 3 * minLarge);
|
||||
producer.send(message);
|
||||
|
||||
session.commit();
|
||||
|
||||
ClientConsumer consumer = session.createConsumer(DIVERT_ADDRESS);
|
||||
ClientMessage receivedFromSourceQueue = consumer.receive(5000);
|
||||
assertNotNull(receivedFromSourceQueue);
|
||||
receivedFromSourceQueue.acknowledge();
|
||||
session.commit();
|
||||
|
||||
crash(session);
|
||||
|
||||
ClientConsumer consumer1 = session.createConsumer(DIVERT_FORWARD_ADDRESS);
|
||||
ClientMessage receivedFromTargetQueue = consumer1.receive(5000);
|
||||
assertNotNull(receivedFromTargetQueue);
|
||||
receivedFromTargetQueue.acknowledge();
|
||||
|
||||
session.commit();
|
||||
|
||||
checkBufferNotReused();
|
||||
}
|
||||
|
||||
private void checkBufferNotReused() throws Exception {
|
||||
assertNotNull("Didn't catch the original buffer!", originalBuffer);
|
||||
assertTrue("Didn't catch the read buffer!", sourceBytes.size() > 0);
|
||||
for (byte[] array : sourceBytes) {
|
||||
assertFalse("Buffer reused!", originalBuffer == array);
|
||||
}
|
||||
}
|
||||
|
||||
private ClientMessage createLargeMessage(ClientSession session, final int largeSize) {
|
||||
ClientMessage message = session.createMessage(true);
|
||||
ActiveMQBuffer bodyBuffer = message.getBodyBuffer();
|
||||
final int propSize = 10240;
|
||||
while (bodyBuffer.writerIndex() < largeSize) {
|
||||
byte[] prop = new byte[propSize];
|
||||
bodyBuffer.writeBytes(prop);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private static void copyThread() {
|
||||
log.debug("_************************ " + Thread.currentThread().getId());
|
||||
copyThread.set(Thread.currentThread().getId());
|
||||
}
|
||||
|
||||
private static void addBytesIn(final byte[] bytes) {
|
||||
if (copyThread.get() != -1 && copyThread.get() == Thread.currentThread().getId()) {
|
||||
sourceBytes.add(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private static void originBuff(final ByteBuffer buff) {
|
||||
if (copyThread.get() != -1 && copyThread.get() == Thread.currentThread().getId()) {
|
||||
originalBuffer = buff.array();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class LatencyTest extends ActiveMQTestBase {
|
||||
private static final Logger log = Logger.getLogger(LatencyTest.class);
|
||||
|
||||
private static void debugLog(String message) {
|
||||
log.debug(message);
|
||||
}
|
||||
|
||||
/*
|
||||
* simple test to make sure connect still works with some network latency built into netty
|
||||
* */
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "trace ClientBootstrap.connect",
|
||||
targetClass = "org.jboss.netty.bootstrap.ClientBootstrap",
|
||||
targetMethod = "connect",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LatencyTest.debugLog(\"netty connecting\")"),
|
||||
@BMRule(
|
||||
name = "sleep OioWorker.run",
|
||||
targetClass = "org.jboss.netty.channel.socket.oio.OioWorker",
|
||||
targetMethod = "run",
|
||||
targetLocation = "ENTRY",
|
||||
action = "Thread.sleep(500)")})
|
||||
public void testLatency() throws Exception {
|
||||
ActiveMQServer server = createServer(createDefaultNettyConfig());
|
||||
server.start();
|
||||
ServerLocator locator = createNettyNonHALocator();
|
||||
ClientSessionFactory factory = createSessionFactory(locator);
|
||||
ClientSession session = factory.createSession();
|
||||
session.close();
|
||||
server.stop();
|
||||
}
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.JMSException;
|
||||
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.plugin.impl.LoggingActiveMQServerPlugin;
|
||||
import org.apache.qpid.jms.JmsConnectionFactory;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* NOTE: this test should be run at log level INFO
|
||||
*
|
||||
* This test checks the LoggingActiveMQServerPlugin is logging expected data with specific property configurations
|
||||
* when client using AMQP
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class LoggingActiveMQServerPluginAMQPTest extends LoggingActiveMQServerPluginTest {
|
||||
|
||||
/**
|
||||
* Aim: test all events are logged when plugin configured with
|
||||
* LOG_ALL_EVENTS
|
||||
*
|
||||
* Overridden as behaviour slightly different for AMQP - consumer closed plugin point called twice
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test logAll EVENT",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogAll() throws Exception {
|
||||
|
||||
//initial plugin
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_ALL_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, true, "log ALL Message_1", 0);
|
||||
sendAndReceive(true, true, "log ALL Message_2", 0);
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals("created connections", 2, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 2, destroyedConnectionLogs.size());
|
||||
assertEquals("created consumer", 2, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 4, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 2, deliveredLogs.size());
|
||||
assertEquals("acked message", 2, ackedLogs.size());
|
||||
assertEquals("sending message", 2, sentLogs.size());
|
||||
assertEquals("routing message", 2, routedLogs.size());
|
||||
assertEquals("queue created", 2, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 2, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test the consumer create/close events are logged when plugin configured with
|
||||
* LOG_CONSUMER_EVENTS
|
||||
*
|
||||
* Overridden as behaviour slightly different for AMQP - consumer closed plugin point seems to be called twice
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_CONSUMER_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogConsumerEvents() throws Exception {
|
||||
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_CONSUMER_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, true, "txtMessage", 0);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 1, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 2, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 0, deliveredLogs.size());
|
||||
assertEquals("acked message", 0, ackedLogs.size());
|
||||
assertEquals("sending message", 0, sentLogs.size());
|
||||
assertEquals("routing message", 0, routedLogs.size());
|
||||
assertEquals("queue created", 0, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 0, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test the session create/close events are logged when plugin configured with
|
||||
* LOG_SESSION_EVENTS
|
||||
*
|
||||
* Overriden as addedMetaData does not seem to be invoked for AMQP
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_SESSION_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogSessionEvents() throws Exception {
|
||||
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_SESSION_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(false,false,"test_message",0);
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 2, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 2, closedSessionLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Connection createActiveMQConnection() throws JMSException {
|
||||
JmsConnectionFactory factory = new JmsConnectionFactory("amqp://localhost:61616");
|
||||
return factory.createConnection();
|
||||
}
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.JMSException;
|
||||
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.plugin.impl.LoggingActiveMQServerPlugin;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
*
|
||||
* NOTE: this test should be run at log level INFO
|
||||
*
|
||||
* This test checks the LoggingActiveMQServerPlugin is logging expected data with specific property configurations
|
||||
* when client using OpenWire
|
||||
*
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class LoggingActiveMQServerPluginOpenWireTest extends LoggingActiveMQServerPluginTest {
|
||||
private static final Logger log = Logger.getLogger(LoggingActiveMQServerPluginOpenWireTest.class);
|
||||
|
||||
/**
|
||||
* Aim: test queue creation are logged when plugin configured with
|
||||
* LOG_INTERNAL_EVENTS
|
||||
*
|
||||
* Overiden as Openwire does not seem to destroy the queue.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test queue creation log",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testQueueCreationLog() throws Exception {
|
||||
|
||||
//initial plugin
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_INTERNAL_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(false, true, "NO_MESSAGE", 0);
|
||||
Thread.sleep(500);
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 0, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 0, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 0, deliveredLogs.size());
|
||||
assertEquals("acked message", 0, ackedLogs.size());
|
||||
assertEquals("sending message", 0, sentLogs.size());
|
||||
assertEquals("routing message", 0, routedLogs.size());
|
||||
assertEquals("queue created", 1, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 0, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test the session create/close events are logged when plugin configured with
|
||||
* LOG_SESSION_EVENTS
|
||||
*
|
||||
* Overriden as
|
||||
* - ceated/closed sessions is invoke 3 times for openwire
|
||||
* - no meta data added to the session .
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_SESSION_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogSessionEvents() throws Exception {
|
||||
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_SESSION_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(false,false,"test_message",0);
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 3, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 3, closedSessionLogs.size());
|
||||
assertEquals("added Metadata logs", 0, addedSessionMetaData.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test all events are logged when plugin configured with
|
||||
* LOG_ALL_EVENTS
|
||||
*
|
||||
* Overridden as behaviour slightly different for queue create/destroy with Openwire
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test logAll EVENT",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogAll() throws Exception {
|
||||
|
||||
//initial plugin
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_ALL_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, true, "log ALL Message_1", 0);
|
||||
sendAndReceive(true, true, "log ALL Message_2", 0);
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
for (String logline : unexpectedLogs) {
|
||||
log.debug(" others events logged >>>>" + logline);
|
||||
}
|
||||
|
||||
assertEquals("created connections", 2, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 2, destroyedConnectionLogs.size());
|
||||
//assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
//assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 2, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 2, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 2, deliveredLogs.size());
|
||||
assertEquals("acked message", 2, ackedLogs.size());
|
||||
assertEquals("sending message", 2, sentLogs.size());
|
||||
assertEquals("routing message", 2, routedLogs.size());
|
||||
assertEquals("queue created", 1, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 0, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Connection createActiveMQConnection() throws JMSException {
|
||||
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616?jms.watchTopicAdvisories=false");
|
||||
return factory.createConnection();
|
||||
}
|
||||
}
|
|
@ -1,546 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.plugin.impl.LoggingActiveMQServerPlugin;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnection;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.jboss.logging.Logger.Level;
|
||||
|
||||
/**
|
||||
* NOTE: this test should be run at log level INFO
|
||||
*
|
||||
* This test checks the LoggingActiveMQServerPlugin is logging expected data with specific property configurations
|
||||
* when using CORE protocol
|
||||
*
|
||||
* Byteman is used to intercept the logged message and uses a helper method to put the messages into seperate lists
|
||||
* based on its content. The test subsequently checks to ensure correct number of logs in each list.
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class LoggingActiveMQServerPluginTest extends ActiveMQTestBase {
|
||||
|
||||
|
||||
//buckets for logging
|
||||
protected static List<String> createdConnectionLogs = new ArrayList<>();
|
||||
protected static List<String> destroyedConnectionLogs = new ArrayList<>();
|
||||
protected static List<String> createdSessionLogs = new ArrayList<>();
|
||||
protected static List<String> closedSessionLogs = new ArrayList<>();
|
||||
protected static List<String> createdConsumerLogs = new ArrayList<>();
|
||||
protected static List<String> closedConsumerLogs = new ArrayList<>();
|
||||
protected static List<String> deliveredLogs = new ArrayList<>();
|
||||
protected static List<String> ackedLogs = new ArrayList<>();
|
||||
protected static List<String> sentLogs = new ArrayList<>();
|
||||
protected static List<String> routedLogs = new ArrayList<>();
|
||||
protected static List<String> createdQueueLogs = new ArrayList<>();
|
||||
protected static List<String> destroyedQueueLogs = new ArrayList<>();
|
||||
protected static List<String> messageExpiredLogs = new ArrayList<>();
|
||||
protected static List<String> unexpectedLogs = new ArrayList<>();
|
||||
protected static List<String> addedSessionMetaData = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Aim: verify connection creation/destroy is logged when LOG_CONNECTION_EVENTS is set
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_CONNECTION_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogConnectEvents() throws Exception {
|
||||
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_CONNECTION_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
Connection connection = createActiveMQConnection();
|
||||
connection.start();
|
||||
Thread.sleep(100);
|
||||
connection.close();
|
||||
|
||||
//ensure logs are collected.
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals("created connections", 1, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 1, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 0, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 0, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 0, deliveredLogs.size());
|
||||
assertEquals("acked message", 0, ackedLogs.size());
|
||||
assertEquals("sending message", 0, sentLogs.size());
|
||||
assertEquals("routing message", 0, routedLogs.size());
|
||||
assertEquals("queue created", 0, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 0, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test the session create/close events are logged when plugin configured with
|
||||
* LOG_SESSION_EVENTS
|
||||
*
|
||||
* NOTE: Session plugin points seem to be invoked twice - did not expect that.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_SESSION_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogSessionEvents() throws Exception {
|
||||
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_SESSION_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(false, false, "test_message", 0);
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 2, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 2, closedSessionLogs.size());
|
||||
assertEquals("added Metadata logs", 2, addedSessionMetaData.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test the consumer create/close events are logged when plugin configured with
|
||||
* LOG_CONSUMER_EVENTS
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_CONSUMER_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogConsumerEvents() throws Exception {
|
||||
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_CONSUMER_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, true, "txtMessage", 0);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 1, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 1, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 0, deliveredLogs.size());
|
||||
assertEquals("acked message", 0, ackedLogs.size());
|
||||
assertEquals("sending message", 0, sentLogs.size());
|
||||
assertEquals("routing message", 0, routedLogs.size());
|
||||
assertEquals("queue created", 0, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 0, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test delivering events are logged when plugin configured with
|
||||
* LOG_DELIVERING_EVENTS
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_DELIVERING_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogDeliveringEvents() throws Exception {
|
||||
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_DELIVERING_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, true, "txtMessage 1", 0);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 0, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 0, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 1, deliveredLogs.size());
|
||||
assertEquals("acked message", 1, ackedLogs.size());
|
||||
assertEquals("sending message", 0, sentLogs.size());
|
||||
assertEquals("routing message", 0, routedLogs.size());
|
||||
assertEquals("queue created", 0, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 0, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test sending events are logged when plugin configured with
|
||||
* LOG_SENDING_EVENTS
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test LOG_SENDING_EVENTS",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogSendingEvents() throws Exception {
|
||||
|
||||
//initial plugin
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_SENDING_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, true, "txtMessage 1", 0);
|
||||
sendAndReceive(true, true, "txtMessage 2", 0);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 0, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 0, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 0, deliveredLogs.size());
|
||||
assertEquals("acked message", 0, ackedLogs.size());
|
||||
assertEquals("sending message", 2, sentLogs.size());
|
||||
assertEquals("routing message", 2, routedLogs.size());
|
||||
assertEquals("queue created", 0, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 0, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test queue creation/destroy are logged when plugin configured with
|
||||
* LOG_INTERNAL_EVENTS
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test queue creation log",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testQueueCreationLog() throws Exception {
|
||||
|
||||
//initial plugin
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_INTERNAL_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(false, true, "NO_MESSAGE", 0);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 0, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 0, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 0, deliveredLogs.size());
|
||||
assertEquals("acked message", 0, ackedLogs.size());
|
||||
assertEquals("sending message", 0, sentLogs.size());
|
||||
assertEquals("routing message", 0, routedLogs.size());
|
||||
assertEquals("queue created", 1, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 1, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test message expiry is logged when plugin configured with
|
||||
* LOG_INTERNAL_EVENTS
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test queue creation log",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testExpireMessageLog() throws Exception {
|
||||
|
||||
//initial plugin
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_INTERNAL_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, false, "message to expiry", 100);
|
||||
Thread.sleep(1000);
|
||||
sendAndReceive(false, true, "NO_MESSAGE", 0);
|
||||
|
||||
assertEquals("created connections", 0, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 0, destroyedConnectionLogs.size());
|
||||
assertEquals("created sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("closed sessions", 0, createdSessionLogs.size());
|
||||
assertEquals("created consumer", 0, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 0, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 0, deliveredLogs.size());
|
||||
assertEquals("acked message", 0, ackedLogs.size());
|
||||
assertEquals("sending message", 0, sentLogs.size());
|
||||
assertEquals("routing message", 0, routedLogs.size());
|
||||
assertEquals("queue created", 1, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 1, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 1, messageExpiredLogs.size());
|
||||
assertEquals("unexpected logs", 0, unexpectedLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aim: test all events are logged when plugin configured with
|
||||
* LOG_ALL_EVENTS
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(name = "test logAll EVENT",
|
||||
targetClass = "org.jboss.logging.Logger",
|
||||
targetMethod = "logv",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.LoggingActiveMQServerPluginTest.infoLog($2, $4, $0)")})
|
||||
public void testLogAll() throws Exception {
|
||||
|
||||
//initial plugin
|
||||
ActiveMQServer activeMQServer = createServerWithLoggingPlugin(LoggingActiveMQServerPlugin.LOG_ALL_EVENTS);
|
||||
activeMQServer.start();
|
||||
|
||||
try {
|
||||
|
||||
sendAndReceive(true, true, "log ALL Message_1", 0);
|
||||
sendAndReceive(true, true, "log ALL Message_2", 0);
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
assertEquals("created connections", 2, createdConnectionLogs.size());
|
||||
assertEquals("destroyed connections", 2, destroyedConnectionLogs.size());
|
||||
assertEquals("created consumer", 2, createdConsumerLogs.size());
|
||||
assertEquals("closed consumer", 2, closedConsumerLogs.size());
|
||||
assertEquals("delivered message", 2, deliveredLogs.size());
|
||||
assertEquals("acked message", 2, ackedLogs.size());
|
||||
assertEquals("sending message", 2, sentLogs.size());
|
||||
assertEquals("routing message", 2, routedLogs.size());
|
||||
assertEquals("queue created", 2, createdQueueLogs.size());
|
||||
assertEquals("queue destroyed", 2, destroyedQueueLogs.size());
|
||||
assertEquals("expired message", 0, messageExpiredLogs.size());
|
||||
|
||||
} finally {
|
||||
activeMQServer.stop();
|
||||
//reset the logs lists
|
||||
clearLogLists();
|
||||
}
|
||||
}
|
||||
|
||||
//collect the log invocation from LoggingActiveMQServerPlugin
|
||||
public static void infoLog(Level level, Object message, org.jboss.logging.Logger logger) {
|
||||
|
||||
//only interested in log level INFO
|
||||
if (!level.equals(Level.INFO)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//only interested in one logger
|
||||
if (!logger.getName().startsWith(LoggingActiveMQServerPlugin.class.getPackage().getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String stringMessage = (String) message;
|
||||
|
||||
if (stringMessage.startsWith("AMQ841000")) {
|
||||
createdConnectionLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841001")) {
|
||||
destroyedConnectionLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841002")) {
|
||||
createdSessionLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841003")) {
|
||||
closedSessionLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841004")) {
|
||||
addedSessionMetaData.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841005")) {
|
||||
createdConsumerLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841006")) {
|
||||
closedConsumerLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841012")) {
|
||||
deliveredLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841014")) {
|
||||
ackedLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841009")) {
|
||||
sentLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841010")) {
|
||||
routedLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841007")) {
|
||||
createdQueueLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841008")) {
|
||||
destroyedQueueLogs.add(stringMessage);
|
||||
} else if (stringMessage.startsWith("AMQ841013")) {
|
||||
messageExpiredLogs.add(stringMessage);
|
||||
} else {
|
||||
unexpectedLogs.add(stringMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----- helper methods ---
|
||||
|
||||
protected void clearLogLists() {
|
||||
createdConnectionLogs.clear();
|
||||
destroyedConnectionLogs.clear();
|
||||
createdSessionLogs.clear();
|
||||
closedSessionLogs.clear();
|
||||
createdConsumerLogs.clear();
|
||||
closedConsumerLogs.clear();
|
||||
deliveredLogs.clear();
|
||||
ackedLogs.clear();
|
||||
sentLogs.clear();
|
||||
routedLogs.clear();
|
||||
createdQueueLogs.clear();
|
||||
destroyedQueueLogs.clear();
|
||||
messageExpiredLogs.clear();
|
||||
unexpectedLogs.clear();
|
||||
addedSessionMetaData.clear();
|
||||
}
|
||||
|
||||
protected ActiveMQServer createServerWithLoggingPlugin(String loggingPluginEventType) throws Exception {
|
||||
//initial plugin
|
||||
LoggingActiveMQServerPlugin loggingActiveMQServerPlugin = new LoggingActiveMQServerPlugin();
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put(loggingPluginEventType, "true");
|
||||
loggingActiveMQServerPlugin.init(properties);
|
||||
|
||||
//register
|
||||
Configuration config = createDefaultConfig(true);
|
||||
config.registerBrokerPlugin(loggingActiveMQServerPlugin);
|
||||
|
||||
return createServer(false, config);
|
||||
}
|
||||
|
||||
protected void sendAndReceive(boolean send,
|
||||
boolean receive,
|
||||
String txtMessage,
|
||||
long expiry) throws JMSException, InterruptedException {
|
||||
Connection connection = createActiveMQConnection();
|
||||
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
connection.start();
|
||||
Queue queue = session.createQueue("TEST.QUEUE");
|
||||
MessageConsumer messageConsumer = null;
|
||||
|
||||
if (receive) {
|
||||
messageConsumer = session.createConsumer(queue);
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
if (send) {
|
||||
MessageProducer messageProducer = session.createProducer(queue);
|
||||
if (expiry > 0) {
|
||||
messageProducer.setTimeToLive(expiry);
|
||||
}
|
||||
messageProducer.send(session.createTextMessage(txtMessage));
|
||||
}
|
||||
if (receive) {
|
||||
messageConsumer.receive(100);
|
||||
messageConsumer.close();
|
||||
}
|
||||
|
||||
session.close();
|
||||
connection.close();
|
||||
}
|
||||
|
||||
protected Connection createActiveMQConnection() throws JMSException {
|
||||
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
|
||||
return (ActiveMQConnection) factory.createConnection();
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.RuntimeMBeanException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ManagementExceptionHandlingTest extends ActiveMQTestBase {
|
||||
private static final Logger log = Logger.getLogger(ManagementExceptionHandlingTest.class);
|
||||
|
||||
protected ActiveMQServer server = null;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
server = createServer(createDefaultNettyConfig());
|
||||
server.getConfiguration().setJMXManagementEnabled(true);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(
|
||||
name = "checking ActiveMQServerControl methods",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl",
|
||||
targetMethod = "createQueue(org.apache.activemq.artemis.api.core.SimpleString, org.apache.activemq.artemis.api.core.RoutingType, org.apache.activemq.artemis.api.core.SimpleString, org.apache.activemq.artemis.api.core.SimpleString, boolean, boolean, int, boolean, boolean)",
|
||||
targetLocation = "EXIT",
|
||||
action = "throw new org.apache.activemq.artemis.api.core.ActiveMQException(\"gotcha\")")})
|
||||
public void testActiveMQServerControl() throws Exception {
|
||||
try {
|
||||
server.getActiveMQServerControl().createQueue(new QueueConfiguration("some.queue").setAddress("some.address").setRoutingType(RoutingType.ANYCAST).toJSON());
|
||||
fail("test should have gotten an exception!");
|
||||
} catch (ActiveMQException e) {
|
||||
fail("Wrong exception got!");
|
||||
} catch (IllegalStateException e) {
|
||||
assertEquals("gotcha", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(rules = {
|
||||
@BMRule(
|
||||
name = "checking ActiveMQServerControl methods",
|
||||
targetClass = "org.apache.activemq.artemis.core.postoffice.impl.PostOfficeImpl",
|
||||
targetMethod = "route(org.apache.activemq.artemis.api.core.Message, boolean)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "throw new org.apache.activemq.artemis.api.core.ActiveMQException(\"gotcha\")")})
|
||||
public void testAddressControl() throws Exception {
|
||||
server.getActiveMQServerControl().createAddress("test.address", "ANYCAST");
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
log.debug("server is " + mbs);
|
||||
ObjectName objectName = new ObjectName("org.apache.activemq.artemis:broker=\"localhost\",component=addresses,address=\"test.address\"");
|
||||
Object[] params = new Object[] {new HashMap(), 3, "aGVsbG8=", true, null, null};
|
||||
String[] signature = new String[] {"java.util.Map", "int", "java.lang.String", "boolean", "java.lang.String", "java.lang.String"};
|
||||
try {
|
||||
mbs.invoke(objectName, "sendMessage", params, signature);
|
||||
fail("test should have gotten an exception!");
|
||||
} catch (RuntimeMBeanException ex) {
|
||||
assertTrue(ex.getCause() instanceof IllegalStateException);
|
||||
IllegalStateException e = (IllegalStateException) ex.getCause();
|
||||
assertEquals("gotcha", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.Queue;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class OrphanedConsumerTest extends ActiveMQTestBase {
|
||||
private static final Logger log = Logger.getLogger(OrphanedConsumerTest.class);
|
||||
|
||||
private static void debugLog(String message) {
|
||||
log.debug(message);
|
||||
}
|
||||
|
||||
private static boolean conditionActive = true;
|
||||
|
||||
public static final boolean isConditionActive() {
|
||||
return conditionActive;
|
||||
}
|
||||
|
||||
public static final void setConditionActive(boolean _conditionActive) {
|
||||
conditionActive = _conditionActive;
|
||||
}
|
||||
|
||||
public static void throwException() throws Exception {
|
||||
throw new InterruptedException("nice.. I interrupted this!");
|
||||
}
|
||||
|
||||
private ActiveMQServer server;
|
||||
|
||||
private ServerLocator locator;
|
||||
|
||||
static ActiveMQServer staticServer;
|
||||
|
||||
/**
|
||||
* {@link #leavingCloseOnTestCountersWhileClosing()} will set this in case of any issues.
|
||||
* the test must then validate for this being null
|
||||
*/
|
||||
static AssertionError verification;
|
||||
|
||||
/**
|
||||
* This static method is an entry point for the byteman rules on {@link #testOrphanedConsumers()}
|
||||
*/
|
||||
public static void leavingCloseOnTestCountersWhileClosing() {
|
||||
if (staticServer.getSessions().size() == 0) {
|
||||
verification = new AssertionError("The session was closed before the consumers, this may cause issues on management leaving Orphaned Consumers!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
setConditionActive(true);
|
||||
/** I'm using the internal method here because closing
|
||||
* this locator on tear down would hang.
|
||||
* as we are tweaking with the internal state and making it fail */
|
||||
locator = internalCreateNonHALocator(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
setConditionActive(false);
|
||||
|
||||
staticServer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is like being two tests in one:
|
||||
* I - validating that any exception during the close wouldn't stop connection from being closed
|
||||
* II - validating that the connection is only removed at the end of the process and you wouldn't see
|
||||
* inconsistencies on management
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "closeExit",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl",
|
||||
targetMethod = "close",
|
||||
targetLocation = "AT EXIT",
|
||||
condition = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.isConditionActive()",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.debugLog(\"throwing stuff\");throw new InterruptedException()"),
|
||||
@BMRule(
|
||||
name = "closeEnter",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl",
|
||||
targetMethod = "close",
|
||||
targetLocation = "ENTRY",
|
||||
condition = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.isConditionActive()",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.leavingCloseOnTestCountersWhileClosing()")})
|
||||
public void testOrphanedConsumers() throws Exception {
|
||||
internalTestOrphanedConsumers(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is like being two tests in one:
|
||||
* I - validating that any exception during the close wouldn't stop connection from being closed
|
||||
* II - validating that the connection is only removed at the end of the process and you wouldn't see
|
||||
* inconsistencies on management
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "closeExit",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl",
|
||||
targetMethod = "close",
|
||||
targetLocation = "AT EXIT",
|
||||
condition = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.isConditionActive()",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.debugLog(\"throwing stuff\");throw new InterruptedException()"),
|
||||
@BMRule(
|
||||
name = "closeEnter",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl",
|
||||
targetMethod = "close",
|
||||
targetLocation = "ENTRY",
|
||||
condition = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.isConditionActive()",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.OrphanedConsumerTest.leavingCloseOnTestCountersWhileClosing()")})
|
||||
public void testOrphanedConsumersByManagement() throws Exception {
|
||||
internalTestOrphanedConsumers(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param useManagement true = it will use a management operation to make the connection failure, false through ping
|
||||
* @throws Exception
|
||||
*/
|
||||
private void internalTestOrphanedConsumers(boolean useManagement) throws Exception {
|
||||
final int NUMBER_OF_MESSAGES = 2;
|
||||
server = createServer(true, true);
|
||||
server.start();
|
||||
staticServer = server;
|
||||
|
||||
// We are not interested on consumer-window-size on this test
|
||||
// We want that every message is delivered
|
||||
// as we asserting for number of consumers available and round-robin on delivery
|
||||
locator.setConsumerWindowSize(-1).setBlockOnNonDurableSend(false).setBlockOnDurableSend(false).setBlockOnAcknowledge(true).setConnectionTTL(1000).setClientFailureCheckPeriod(100).setReconnectAttempts(0);
|
||||
|
||||
ClientSessionFactoryImpl sf = (ClientSessionFactoryImpl) createSessionFactory(locator);
|
||||
|
||||
ClientSession session = sf.createSession(true, true, 0);
|
||||
|
||||
session.createQueue(new QueueConfiguration("queue1").setAddress("queue"));
|
||||
session.createQueue(new QueueConfiguration("queue2").setAddress("queue"));
|
||||
|
||||
ClientProducer prod = session.createProducer("queue");
|
||||
|
||||
ClientConsumer consumer = session.createConsumer("queue1");
|
||||
ClientConsumer consumer2 = session.createConsumer("queue2");
|
||||
|
||||
Queue queue1 = server.locateQueue(new SimpleString("queue1"));
|
||||
|
||||
Queue queue2 = server.locateQueue(new SimpleString("queue2"));
|
||||
|
||||
session.start();
|
||||
|
||||
if (!useManagement) {
|
||||
sf.stopPingingAfterOne();
|
||||
|
||||
for (long timeout = System.currentTimeMillis() + 6000; timeout > System.currentTimeMillis() && server.getConnectionCount() != 0; ) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
|
||||
// an extra second to avoid races of something closing the session while we are asserting it
|
||||
Thread.sleep(1000);
|
||||
} else {
|
||||
server.getActiveMQServerControl().closeConnectionsForAddress("127.0.0.1");
|
||||
}
|
||||
|
||||
if (verification != null) {
|
||||
throw verification;
|
||||
}
|
||||
|
||||
assertEquals(0, queue1.getConsumerCount());
|
||||
assertEquals(0, queue2.getConsumerCount());
|
||||
|
||||
setConditionActive(false);
|
||||
|
||||
locator = internalCreateNonHALocator(true).setBlockOnNonDurableSend(false).setBlockOnDurableSend(false).setBlockOnAcknowledge(true).setReconnectAttempts(0).setConsumerWindowSize(-1);
|
||||
|
||||
sf = (ClientSessionFactoryImpl) locator.createSessionFactory();
|
||||
session = sf.createSession(true, true, 0);
|
||||
|
||||
session.start();
|
||||
|
||||
prod = session.createProducer("queue");
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
|
||||
ClientMessage message = session.createMessage(true);
|
||||
message.putIntProperty("i", i);
|
||||
prod.send(message);
|
||||
}
|
||||
|
||||
consumer = session.createConsumer("queue1");
|
||||
consumer2 = session.createConsumer("queue2");
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
|
||||
assertNotNull(consumer.receive(5000));
|
||||
assertNotNull(consumer2.receive(5000));
|
||||
}
|
||||
|
||||
session.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import 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 org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQMessageConsumer;
|
||||
import org.apache.activemq.artemis.tests.util.JMSTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class PacketFailureTest extends JMSTestBase {
|
||||
|
||||
private Queue queue;
|
||||
static boolean pause = false;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
queue = createQueue("TestQueue");
|
||||
}
|
||||
|
||||
@Test(timeout = 20000)
|
||||
@BMRule(
|
||||
name = "blow-up",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext",
|
||||
targetMethod = "handleReceivedMessagePacket(org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionReceiveMessage)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "throw new Exception()")
|
||||
public void testFailureToHandlePacket() throws Exception {
|
||||
final int MESSAGE_COUNT = 20;
|
||||
Connection sendConnection = null;
|
||||
Connection connection = null;
|
||||
try {
|
||||
((ActiveMQConnectionFactory)cf).setReconnectAttempts(0);
|
||||
sendConnection = cf.createConnection();
|
||||
final Session sendSession = sendConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
final MessageProducer producer = sendSession.createProducer(queue);
|
||||
|
||||
for (int j = 0; j < MESSAGE_COUNT; j++) {
|
||||
TextMessage message = sendSession.createTextMessage();
|
||||
|
||||
message.setText("Message" + j);
|
||||
|
||||
producer.send(message);
|
||||
}
|
||||
|
||||
producer.close();
|
||||
sendSession.close();
|
||||
|
||||
connection = cf.createConnection();
|
||||
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageConsumer consumer = session.createConsumer(queue);
|
||||
connection.start();
|
||||
|
||||
Message message = consumer.receive(1000);
|
||||
assertNull(message);
|
||||
assertTrue(((ActiveMQMessageConsumer) consumer).isClosed());
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
if (sendConnection != null) {
|
||||
sendConnection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p/>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.Queue;
|
||||
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.Wait;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class PagingOMETest extends ActiveMQTestBase {
|
||||
|
||||
private ServerLocator locator;
|
||||
private ActiveMQServer server;
|
||||
private ClientSessionFactory sf;
|
||||
static final int MESSAGE_SIZE = 1024; // 1k
|
||||
|
||||
private static final int RECEIVE_TIMEOUT = 5000;
|
||||
|
||||
private static final int PAGE_MAX = 100 * 1024;
|
||||
|
||||
private static final int PAGE_SIZE = 10 * 1024;
|
||||
|
||||
static final SimpleString ADDRESS = new SimpleString("SimpleAddress");
|
||||
|
||||
static boolean failureActive = false;
|
||||
|
||||
public static void refCheck() {
|
||||
if (failureActive) {
|
||||
throw new OutOfMemoryError("fake error");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
failureActive = false;
|
||||
locator = createInVMNonHALocator();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "fakeOME",
|
||||
targetClass = "org.apache.activemq.artemis.core.paging.cursor.PagedReferenceImpl",
|
||||
targetMethod = "getPagedMessage",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.PagingOMETest.refCheck()")})
|
||||
public void testPageCleanup() throws Exception {
|
||||
clearDataRecreateServerDirs();
|
||||
|
||||
Configuration config = createDefaultConfig(false);
|
||||
|
||||
config.setJournalSyncNonTransactional(false);
|
||||
|
||||
HashMap<String, AddressSettings> map = new HashMap<>();
|
||||
AddressSettings value = new AddressSettings();
|
||||
map.put(ADDRESS.toString(), value);
|
||||
server = createServer(true, config, PAGE_SIZE, PAGE_MAX, map);
|
||||
|
||||
server.start();
|
||||
|
||||
final int numberOfMessages = 2;
|
||||
|
||||
locator = createInVMNonHALocator();
|
||||
|
||||
locator.setBlockOnNonDurableSend(true);
|
||||
locator.setBlockOnDurableSend(true);
|
||||
locator.setBlockOnAcknowledge(false);
|
||||
locator.setConsumerWindowSize(0);
|
||||
|
||||
sf = createSessionFactory(locator);
|
||||
|
||||
ClientSession session = sf.createSession(false, false, false);
|
||||
|
||||
session.createQueue(new QueueConfiguration(ADDRESS));
|
||||
|
||||
Queue queue = server.locateQueue(ADDRESS);
|
||||
queue.getPageSubscription().getPagingStore().startPaging();
|
||||
|
||||
Assert.assertTrue(queue.getPageSubscription().getPagingStore().isPaging());
|
||||
|
||||
ClientProducer producer = session.createProducer(PagingOMETest.ADDRESS);
|
||||
|
||||
ClientMessage message = null;
|
||||
|
||||
byte[] body = new byte[MESSAGE_SIZE];
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(body);
|
||||
|
||||
for (int j = 1; j <= MESSAGE_SIZE; j++) {
|
||||
bb.put(getSamplebyte(j));
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberOfMessages; i++) {
|
||||
message = session.createMessage(true);
|
||||
|
||||
ActiveMQBuffer bodyLocal = message.getBodyBuffer();
|
||||
|
||||
bodyLocal.writeBytes(body);
|
||||
|
||||
producer.send(message);
|
||||
if (i % 1000 == 0) {
|
||||
session.commit();
|
||||
}
|
||||
}
|
||||
session.commit();
|
||||
|
||||
session = sf.createSession(false, false, false);
|
||||
|
||||
session.start();
|
||||
|
||||
Wait.assertTrue(() -> numberOfMessages == queue.getMessageCount());
|
||||
|
||||
// The consumer has to be created after the queue.getMessageCount assertion
|
||||
// otherwise delivery could alter the messagecount and give us a false failure
|
||||
ClientConsumer consumer = session.createConsumer(PagingOMETest.ADDRESS);
|
||||
ClientMessage msg = null;
|
||||
|
||||
msg = consumer.receive(1000);
|
||||
|
||||
failureActive = true;
|
||||
msg.individualAcknowledge();
|
||||
try {
|
||||
session.commit();
|
||||
Assert.fail("exception expected");
|
||||
} catch (Exception expected) {
|
||||
}
|
||||
failureActive = false;
|
||||
session.rollback();
|
||||
|
||||
session.close();
|
||||
|
||||
sf.close();
|
||||
|
||||
locator.close();
|
||||
|
||||
server.stop();
|
||||
|
||||
server.start();
|
||||
|
||||
locator = createInVMNonHALocator();
|
||||
|
||||
locator.setBlockOnNonDurableSend(true);
|
||||
locator.setBlockOnDurableSend(true);
|
||||
locator.setBlockOnAcknowledge(false);
|
||||
locator.setConsumerWindowSize(0);
|
||||
|
||||
sf = createSessionFactory(locator);
|
||||
|
||||
session = sf.createSession(false, false, false);
|
||||
|
||||
consumer = session.createConsumer(PagingOMETest.ADDRESS);
|
||||
|
||||
session.start();
|
||||
|
||||
for (int i = 0; i < numberOfMessages; i++) {
|
||||
msg = consumer.receive(1000);
|
||||
Assert.assertNotNull(msg);
|
||||
msg.individualAcknowledge();
|
||||
}
|
||||
Assert.assertNull(consumer.receiveImmediate());
|
||||
session.commit();
|
||||
|
||||
session.close();
|
||||
sf.close();
|
||||
server.stop();
|
||||
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class QueueDeploymentFailedTest extends ActiveMQTestBase {
|
||||
|
||||
@Test
|
||||
|
||||
@BMRule(name = "blow up queue deployment",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl",
|
||||
targetMethod = "createQueue(SimpleString,RoutingType,SimpleString,SimpleString,SimpleString,boolean,boolean,boolean,boolean,boolean,int,boolean,boolean,boolean,int,long,boolean",
|
||||
targetLocation = "EXIT",
|
||||
action = "throw new IllegalStateException(\"test exception\")")
|
||||
public void testQueueDeploymentFailure() throws Exception {
|
||||
ActiveMQServer server = createServer(false, createDefaultNettyConfig());
|
||||
String address = UUID.randomUUID().toString();
|
||||
server.getConfiguration().addAddressConfiguration(new CoreAddressConfiguration().setName(address).addRoutingType(RoutingType.ANYCAST).addQueueConfiguration(new QueueConfiguration(UUID.randomUUID().toString()).setRoutingType(RoutingType.ANYCAST).setAddress(address)));
|
||||
server.start();
|
||||
assertTrue(server.getRemotingService().isStarted());
|
||||
}
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal;
|
||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionInternal;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ServerConsumer;
|
||||
import org.apache.activemq.artemis.core.server.ServerSession;
|
||||
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class RaceOnClosingConsumerWhileReconnecting extends ActiveMQTestBase {
|
||||
static RemotingConnection conn;
|
||||
|
||||
static ClientConsumer consumer;
|
||||
|
||||
protected ActiveMQServer server = null;
|
||||
|
||||
protected ClientSessionFactoryInternal sf = null;
|
||||
|
||||
protected ClientSessionInternal session = null;
|
||||
|
||||
protected final SimpleString queueName1 = new SimpleString("my_queue_one");
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
conn = null;
|
||||
consumer = null;
|
||||
server = createServer(true, true);
|
||||
server.start();
|
||||
|
||||
SimpleString addressName1 = new SimpleString("my_address_one");
|
||||
|
||||
server.addAddressInfo(new AddressInfo(addressName1, RoutingType.ANYCAST));
|
||||
server.createQueue(new QueueConfiguration(queueName1).setAddress(addressName1).setRoutingType(RoutingType.ANYCAST));
|
||||
|
||||
final long retryInterval = 500;
|
||||
final double retryMultiplier = 1d;
|
||||
final int reconnectAttempts = 10;
|
||||
ServerLocator locator = createFactory(true).setCallFailoverTimeout(0).setCallTimeout(2000).setRetryInterval(retryInterval).setRetryIntervalMultiplier(retryMultiplier).setReconnectAttempts(reconnectAttempts).setConfirmationWindowSize(-1);
|
||||
sf = (ClientSessionFactoryInternal) createSessionFactory(locator);
|
||||
session = (ClientSessionInternal)sf.createSession(false, true, true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (session != null) {
|
||||
session.close();
|
||||
}
|
||||
if (sf != null) {
|
||||
sf.close();
|
||||
}
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
conn = null;
|
||||
consumer = null;
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "session.removeConsumer wait",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientSessionImpl",
|
||||
targetMethod = "removeConsumer(org.apache.activemq.artemis.core.client.impl.ClientConsumerInternal)",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnClosingConsumerWhileReconnecting.waitForReconnection();")})
|
||||
public void testClosingConsumerBeforeReconnecting() throws Exception {
|
||||
conn = session.getConnection();
|
||||
|
||||
ClientConsumer clientConsumer1 = session.createConsumer(queueName1);
|
||||
ClientConsumer clientConsumer2 = session.createConsumer(queueName1);
|
||||
clientConsumer1.close();
|
||||
|
||||
Thread.sleep(500);
|
||||
Set<ServerConsumer> serverConsumers = server.getSessionByID(session.getName()).getServerConsumers();
|
||||
ServerConsumer serverConsumer = serverConsumers.iterator().next();
|
||||
assertEquals(1, serverConsumers.size());
|
||||
assertEquals(clientConsumer2.getConsumerContext().getId(), serverConsumer.getID());
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "session.closeConsumer before recreating consumer",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientSessionImpl",
|
||||
targetMethod = "handleFailover",
|
||||
targetLocation = "AFTER WRITE $consumerInternal 1",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnClosingConsumerWhileReconnecting.closeConsumer();")})
|
||||
public void testClosingConsumerBeforeRecreatingOneConsumer() throws Exception {
|
||||
RemotingConnection conn = session.getConnection();
|
||||
|
||||
ClientConsumer clientConsumer1 = session.createConsumer(queueName1);
|
||||
consumer = clientConsumer1;
|
||||
conn.fail(new ActiveMQNotConnectedException());
|
||||
|
||||
Thread.sleep(500);
|
||||
Set<ServerConsumer> serverConsumers = server.getSessionByID(session.getName()).getServerConsumers();
|
||||
assertEquals(0, serverConsumers.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "session.closeConsumer before recreating consumer",
|
||||
targetClass = "org.apache.activemq.artemis.core.client.impl.ClientSessionImpl",
|
||||
targetMethod = "handleFailover",
|
||||
targetLocation = "AFTER WRITE $consumerInternal 1",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnClosingConsumerWhileReconnecting.closeConsumer();")})
|
||||
public void testClosingConsumerBeforeRecreatingTwoConsumers() throws Exception {
|
||||
RemotingConnection conn = session.getConnection();
|
||||
|
||||
ClientConsumer clientConsumer1 = session.createConsumer(queueName1);
|
||||
ClientConsumer clientConsumer2 = session.createConsumer(queueName1);
|
||||
consumer = clientConsumer1;
|
||||
conn.fail(new ActiveMQNotConnectedException());
|
||||
|
||||
Thread.sleep(500);
|
||||
ServerSession serverSession = server.getSessionByID(session.getName());
|
||||
assertNotNull(serverSession);
|
||||
Set<ServerConsumer> serverConsumers = serverSession.getServerConsumers();
|
||||
ServerConsumer serverConsumer = serverConsumers.iterator().next();
|
||||
assertEquals(1, serverConsumers.size());
|
||||
assertEquals(clientConsumer2.getConsumerContext().getId(), serverConsumer.getID());
|
||||
}
|
||||
|
||||
public static void closeConsumer() {
|
||||
if (consumer != null) {
|
||||
try {
|
||||
consumer.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
consumer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void waitForReconnection() {
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.fail(new ActiveMQNotConnectedException());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
conn = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,209 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p/>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.message.impl.CoreMessage;
|
||||
import org.apache.activemq.artemis.core.paging.PagingStore;
|
||||
import org.apache.activemq.artemis.core.paging.cursor.PagedReference;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.Queue;
|
||||
import org.apache.activemq.artemis.core.server.impl.RoutingContextImpl;
|
||||
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.utils.RandomUtil;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class RaceOnCursorIteratorTest extends ActiveMQTestBase {
|
||||
|
||||
private static ServerLocator locator;
|
||||
|
||||
private static ActiveMQServer server;
|
||||
|
||||
private static ClientSessionFactory sf;
|
||||
|
||||
private static ClientSession session;
|
||||
|
||||
private static Queue queue;
|
||||
|
||||
private static final ReentrantReadWriteLock.ReadLock lock = new ReentrantReadWriteLock().readLock();
|
||||
|
||||
private static final int PAGE_MAX = 100 * 1024;
|
||||
|
||||
private static final int PAGE_SIZE = 10 * 1024;
|
||||
|
||||
static final SimpleString ADDRESS = new SimpleString("SimpleAddress");
|
||||
|
||||
static boolean skipLivePageCache = false;
|
||||
|
||||
static boolean skipNullPageCache = false;
|
||||
|
||||
static boolean moveNextPageCalled = false;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
skipLivePageCache = false;
|
||||
skipNullPageCache = false;
|
||||
moveNextPageCalled = false;
|
||||
locator = createInVMNonHALocator();
|
||||
|
||||
clearDataRecreateServerDirs();
|
||||
|
||||
Configuration config = createDefaultConfig(false);
|
||||
|
||||
config.setJournalSyncNonTransactional(false);
|
||||
|
||||
HashMap<String, AddressSettings> map = new HashMap<>();
|
||||
AddressSettings value = new AddressSettings();
|
||||
map.put(ADDRESS.toString(), value);
|
||||
server = createServer(true, config, PAGE_SIZE, PAGE_MAX, map);
|
||||
|
||||
server.start();
|
||||
|
||||
locator = createInVMNonHALocator();
|
||||
|
||||
locator.setBlockOnNonDurableSend(true);
|
||||
locator.setBlockOnDurableSend(true);
|
||||
locator.setBlockOnAcknowledge(false);
|
||||
locator.setConsumerWindowSize(0);
|
||||
|
||||
sf = createSessionFactory(locator);
|
||||
|
||||
session = sf.createSession(false, true, true);
|
||||
|
||||
session.createQueue(new QueueConfiguration(ADDRESS));
|
||||
|
||||
queue = server.locateQueue(ADDRESS);
|
||||
queue.getPageSubscription().getPagingStore().startPaging();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
session.close();
|
||||
sf.close();
|
||||
locator.close();
|
||||
server.stop();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public static void raceAddLivePageCache() throws Exception {
|
||||
if (skipLivePageCache) {
|
||||
createMessage(1);
|
||||
|
||||
queue.getPageSubscription().getPagingStore().forceAnotherPage();
|
||||
|
||||
createMessage(2);
|
||||
}
|
||||
moveNextPageCalled = true;
|
||||
}
|
||||
|
||||
public static void raceAddTwoCaches() throws Exception {
|
||||
if (skipNullPageCache && moveNextPageCalled) {
|
||||
createMessage(1);
|
||||
|
||||
queue.getPageSubscription().getPagingStore().forceAnotherPage();
|
||||
|
||||
createMessage(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "raceLiveCache",
|
||||
targetClass = "org.apache.activemq.artemis.core.paging.cursor.impl.PageSubscriptionImpl",
|
||||
targetMethod = "moveNextPage",
|
||||
targetLocation = "EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnCursorIteratorTest.raceAddLivePageCache()")})
|
||||
public void testSkipLivePageCache() {
|
||||
skipLivePageCache = true;
|
||||
// Simulate scenario #1 depicted in https://issues.apache.org/jira/browse/ARTEMIS-2418
|
||||
PagedReference ref = queue.getPageSubscription().iterator().next();
|
||||
assertTrue("first msg should not be " + (ref == null ? "null" : ref.getPagedMessage().getMessage().getMessageID()),
|
||||
ref == null || ref.getPagedMessage().getMessage().getMessageID() == 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "raceLiveCache",
|
||||
targetClass = "org.apache.activemq.artemis.core.paging.cursor.impl.PageSubscriptionImpl",
|
||||
targetMethod = "moveNextPage",
|
||||
targetLocation = "EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnCursorIteratorTest.raceAddLivePageCache()"),
|
||||
@BMRule(
|
||||
name = "raceNullCache",
|
||||
targetClass = "org.apache.activemq.artemis.core.paging.cursor.impl.PageCursorProviderImpl",
|
||||
targetMethod = "getPageCache",
|
||||
targetLocation = "EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnCursorIteratorTest.raceAddTwoCaches()")})
|
||||
public void testSkipNullPageCache() throws Exception {
|
||||
skipNullPageCache = true;
|
||||
// Simulate scenario #2 depicted in https://issues.apache.org/jira/browse/ARTEMIS-2418
|
||||
queue.getPageSubscription().getPagingStore().getCurrentPage().close(false);
|
||||
|
||||
PagedReference ref = queue.getPageSubscription().iterator().next();
|
||||
assertTrue("first msg should not be " + (ref == null ? "null" : ref.getPagedMessage().getMessage().getMessageID()),
|
||||
ref == null || ref.getPagedMessage().getMessage().getMessageID() == 1);
|
||||
}
|
||||
|
||||
private static CoreMessage createMessage(final long id) throws Exception {
|
||||
ActiveMQBuffer buffer = createRandomBuffer(0, 10);
|
||||
PagingStore pagingStore = queue.getPageSubscription().getPagingStore();
|
||||
|
||||
CoreMessage msg = new CoreMessage(id, 50 + buffer.capacity());
|
||||
|
||||
msg.setAddress(ADDRESS);
|
||||
|
||||
msg.getBodyBuffer().resetReaderIndex();
|
||||
msg.getBodyBuffer().resetWriterIndex();
|
||||
|
||||
msg.getBodyBuffer().writeBytes(buffer, buffer.capacity());
|
||||
|
||||
final RoutingContextImpl ctx = new RoutingContextImpl(null);
|
||||
ctx.addQueue(ADDRESS, queue);
|
||||
pagingStore.page(msg, ctx.getTransaction(), ctx.getContextListing(ADDRESS));
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
protected static ActiveMQBuffer createRandomBuffer(final long id, final int size) {
|
||||
return RandomUtil.randomBuffer(size, id);
|
||||
}
|
||||
}
|
|
@ -1,282 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MapMessage;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.FailoverEventListener;
|
||||
import org.apache.activemq.artemis.api.core.client.FailoverEventType;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.CoreQueueConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.impl.SharedNothingBackupActivation;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnection;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.ReplicatedBackupUtils;
|
||||
import org.apache.activemq.artemis.tests.util.TransportConfigurationUtils;
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This test will add more bytes to the large message while still syncing.
|
||||
* At the time of writing I couldn't replicate any issues, but I'm keeping it here to validate the impl
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class RaceOnSyncLargeMessageOverReplication2Test extends ActiveMQTestBase {
|
||||
private static final Logger log = Logger.getLogger(RaceOnSyncLargeMessageOverReplication2Test.class);
|
||||
|
||||
public static int messageChunkCount = 0;
|
||||
|
||||
private static ActiveMQServer backupServer;
|
||||
private static ActiveMQServer liveServer;
|
||||
|
||||
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616?minLargeMessageSize=10000&HA=true&retryInterval=100&reconnectAttempts=-1&producerWindowSize=10000");
|
||||
ActiveMQConnection connection;
|
||||
Session session;
|
||||
Queue queue;
|
||||
MessageProducer producer;
|
||||
|
||||
Configuration backupConfig;
|
||||
|
||||
Configuration liveConfig;
|
||||
|
||||
// To inform the main thread the condition is met
|
||||
static final ReusableLatch flagChunkEntered = new ReusableLatch(1);
|
||||
// To wait while the condition is worked out
|
||||
static final ReusableLatch flagChunkWait = new ReusableLatch(1);
|
||||
|
||||
// To inform the main thread the condition is met
|
||||
static final ReusableLatch flagSyncEntered = new ReusableLatch(1);
|
||||
// To wait while the condition is worked out
|
||||
static final ReusableLatch flagSyncWait = new ReusableLatch(1);
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
log.debug("Tmp::" + getTemporaryDir());
|
||||
|
||||
flagChunkEntered.setCount(1);
|
||||
flagChunkWait.setCount(1);
|
||||
|
||||
flagSyncEntered.setCount(1);
|
||||
flagSyncWait.setCount(1);
|
||||
|
||||
messageChunkCount = 0;
|
||||
|
||||
TransportConfiguration liveConnector = TransportConfigurationUtils.getNettyConnector(true, 0);
|
||||
TransportConfiguration liveAcceptor = TransportConfigurationUtils.getNettyAcceptor(true, 0);
|
||||
TransportConfiguration backupConnector = TransportConfigurationUtils.getNettyConnector(false, 0);
|
||||
TransportConfiguration backupAcceptor = TransportConfigurationUtils.getNettyAcceptor(false, 0);
|
||||
|
||||
backupConfig = createDefaultInVMConfig().setBindingsDirectory(getBindingsDir(0, true)).
|
||||
setJournalDirectory(getJournalDir(0, true)).setPagingDirectory(getPageDir(0, true)).
|
||||
setLargeMessagesDirectory(getLargeMessagesDir(0, true));
|
||||
|
||||
liveConfig = createDefaultInVMConfig();
|
||||
|
||||
ReplicatedBackupUtils.configureReplicationPair(backupConfig, backupConnector, backupAcceptor, liveConfig, liveConnector, liveAcceptor);
|
||||
|
||||
liveServer = createServer(liveConfig);
|
||||
liveServer.getConfiguration().addQueueConfiguration(new CoreQueueConfiguration().setName("Queue").setAddress("Queue"));
|
||||
liveServer.start();
|
||||
|
||||
waitForServerToStart(liveServer);
|
||||
|
||||
// Just to make sure the expression worked
|
||||
Assert.assertEquals(10000, factory.getMinLargeMessageSize());
|
||||
Assert.assertEquals(10000, factory.getProducerWindowSize());
|
||||
Assert.assertEquals(100, factory.getRetryInterval());
|
||||
Assert.assertEquals(-1, factory.getReconnectAttempts());
|
||||
Assert.assertTrue(factory.isHA());
|
||||
|
||||
connection = (ActiveMQConnection) factory.createConnection();
|
||||
session = connection.createSession(true, Session.SESSION_TRANSACTED);
|
||||
queue = session.createQueue("Queue");
|
||||
producer = session.createProducer(queue);
|
||||
|
||||
}
|
||||
|
||||
private void startBackup() throws Exception {
|
||||
backupServer = createServer(backupConfig);
|
||||
backupServer.start();
|
||||
|
||||
waitForServerToStart(backupServer);
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServers() throws Exception {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
if (backupServer != null) {
|
||||
backupServer.stop();
|
||||
backupServer = null;
|
||||
}
|
||||
|
||||
if (liveServer != null) {
|
||||
liveServer.stop();
|
||||
liveServer = null;
|
||||
}
|
||||
|
||||
backupServer = liveServer = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "InterruptSending",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext",
|
||||
targetMethod = "sendLargeMessageChunk",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnSyncLargeMessageOverReplication2Test.messageChunkSent();"),
|
||||
@BMRule(
|
||||
name = "InterruptSync",
|
||||
targetClass = "org.apache.activemq.artemis.core.persistence.impl.journal.JournalStorageManager",
|
||||
targetMethod = "sendLargeMessageFiles",
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnSyncLargeMessageOverReplication2Test.syncLargeMessage();")})
|
||||
public void testSendLargeMessage() throws Exception {
|
||||
|
||||
final CountDownLatch failedOver = new CountDownLatch(1);
|
||||
connection.setFailoverListener(new FailoverEventListener() {
|
||||
@Override
|
||||
public void failoverEvent(FailoverEventType eventType) {
|
||||
failedOver.countDown();
|
||||
}
|
||||
});
|
||||
Thread t;
|
||||
|
||||
{
|
||||
final MapMessage message = createLargeMessage();
|
||||
|
||||
t = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
producer.send(message);
|
||||
session.commit();
|
||||
} catch (JMSException expected) {
|
||||
expected.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
t.start();
|
||||
|
||||
// I'm trying to simulate the following race here:
|
||||
// The message is syncing while the client is already sending the body of the message
|
||||
|
||||
Assert.assertTrue(flagChunkEntered.await(10, TimeUnit.SECONDS));
|
||||
|
||||
startBackup();
|
||||
|
||||
Assert.assertTrue(flagSyncEntered.await(10, TimeUnit.SECONDS));
|
||||
|
||||
flagChunkWait.countDown();
|
||||
|
||||
t.join(5000);
|
||||
|
||||
log.debug("Thread joined");
|
||||
|
||||
Assert.assertFalse(t.isAlive());
|
||||
|
||||
flagSyncWait.countDown();
|
||||
|
||||
Assert.assertTrue(((SharedNothingBackupActivation) backupServer.getActivation()).waitForBackupSync(10, TimeUnit.SECONDS));
|
||||
|
||||
waitForRemoteBackup(connection.getSessionFactory(), 30);
|
||||
|
||||
liveServer.fail(true);
|
||||
|
||||
Assert.assertTrue(failedOver.await(10, TimeUnit.SECONDS));
|
||||
|
||||
{
|
||||
MessageConsumer consumer = session.createConsumer(queue);
|
||||
|
||||
connection.start();
|
||||
|
||||
MapMessage message = (MapMessage) consumer.receive(5000);
|
||||
|
||||
Assert.assertNotNull(message);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Assert.assertEquals(1024 * 1024, message.getBytes("test" + i).length);
|
||||
}
|
||||
|
||||
session.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public static void syncLargeMessage() {
|
||||
|
||||
try {
|
||||
flagSyncEntered.countDown();
|
||||
flagSyncWait.await(100, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void messageChunkSent() {
|
||||
messageChunkCount++;
|
||||
|
||||
try {
|
||||
if (messageChunkCount == 1) {
|
||||
flagChunkEntered.countDown();
|
||||
flagChunkWait.await(10, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private MapMessage createLargeMessage() throws JMSException {
|
||||
MapMessage message = session.createMapMessage();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
message.setBytes("test" + i, new byte[1024 * 1024]);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MapMessage;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.FailoverEventListener;
|
||||
import org.apache.activemq.artemis.api.core.client.FailoverEventType;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.CoreQueueConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnection;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.ReplicatedBackupUtils;
|
||||
import org.apache.activemq.artemis.tests.util.TransportConfigurationUtils;
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This test will validate the sync of large messages will not lose any messages in a specific scenario.
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class RaceOnSyncLargeMessageOverReplicationTest extends ActiveMQTestBase {
|
||||
private static final Logger log = Logger.getLogger(RaceOnSyncLargeMessageOverReplicationTest.class);
|
||||
|
||||
private static ActiveMQServer backupServer;
|
||||
private static ActiveMQServer liveServer;
|
||||
|
||||
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616?minLargeMessageSize=10000&HA=true&retryInterval=100&reconnectAttempts=-1&producerWindowSize=10000");
|
||||
ActiveMQConnection connection;
|
||||
Session session;
|
||||
Queue queue;
|
||||
MessageProducer producer;
|
||||
|
||||
Configuration backupConfig;
|
||||
|
||||
Configuration liveConfig;
|
||||
|
||||
// To inform the main thread the condition is met
|
||||
static final ReusableLatch flagArrived = new ReusableLatch(1);
|
||||
// To wait while the condition is worked out
|
||||
static final ReusableLatch flagWait = new ReusableLatch(1);
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
log.debug("Tmp::" + getTemporaryDir());
|
||||
|
||||
flagArrived.setCount(1);
|
||||
flagWait.setCount(1);
|
||||
|
||||
TransportConfiguration liveConnector = TransportConfigurationUtils.getNettyConnector(true, 0);
|
||||
TransportConfiguration liveAcceptor = TransportConfigurationUtils.getNettyAcceptor(true, 0);
|
||||
TransportConfiguration backupConnector = TransportConfigurationUtils.getNettyConnector(false, 0);
|
||||
TransportConfiguration backupAcceptor = TransportConfigurationUtils.getNettyAcceptor(false, 0);
|
||||
|
||||
backupConfig = createDefaultInVMConfig().setBindingsDirectory(getBindingsDir(0, true)).
|
||||
setJournalDirectory(getJournalDir(0, true)).setPagingDirectory(getPageDir(0, true)).
|
||||
setLargeMessagesDirectory(getLargeMessagesDir(0, true));
|
||||
|
||||
liveConfig = createDefaultInVMConfig();
|
||||
|
||||
ReplicatedBackupUtils.configureReplicationPair(backupConfig, backupConnector, backupAcceptor, liveConfig, liveConnector, liveAcceptor);
|
||||
|
||||
liveServer = createServer(liveConfig);
|
||||
liveServer.getConfiguration().addQueueConfiguration(new CoreQueueConfiguration().setName("Queue").setAddress("Queue"));
|
||||
liveServer.start();
|
||||
|
||||
waitForServerToStart(liveServer);
|
||||
|
||||
// Just to make sure the expression worked
|
||||
Assert.assertEquals(10000, factory.getMinLargeMessageSize());
|
||||
Assert.assertEquals(10000, factory.getProducerWindowSize());
|
||||
Assert.assertEquals(100, factory.getRetryInterval());
|
||||
Assert.assertEquals(-1, factory.getReconnectAttempts());
|
||||
Assert.assertTrue(factory.isHA());
|
||||
|
||||
connection = (ActiveMQConnection) factory.createConnection();
|
||||
session = connection.createSession(true, Session.SESSION_TRANSACTED);
|
||||
queue = session.createQueue("Queue");
|
||||
producer = session.createProducer(queue);
|
||||
|
||||
}
|
||||
|
||||
private void startBackup() throws Exception {
|
||||
backupServer = createServer(backupConfig);
|
||||
backupServer.start();
|
||||
|
||||
waitForServerToStart(backupServer);
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServers() throws Exception {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
if (backupServer != null) {
|
||||
backupServer.stop();
|
||||
backupServer = null;
|
||||
}
|
||||
|
||||
if (liveServer != null) {
|
||||
liveServer.stop();
|
||||
liveServer = null;
|
||||
}
|
||||
|
||||
backupServer = liveServer = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* simple test to induce a potential race condition where the server's acceptors are active, but the server's
|
||||
* state != STARTED
|
||||
*/
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "InterruptSync",
|
||||
targetClass = "org.apache.activemq.artemis.core.persistence.impl.journal.JournalStorageManager",
|
||||
targetMethod = "createLargeMessage(long,org.apache.activemq.artemis.core.message.impl.MessageInternal)",
|
||||
targetLocation = "EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.RaceOnSyncLargeMessageOverReplicationTest.syncLargeMessage();")})
|
||||
public void testSendLargeMessage() throws Exception {
|
||||
|
||||
final CountDownLatch failedOver = new CountDownLatch(1);
|
||||
connection.setFailoverListener(new FailoverEventListener() {
|
||||
@Override
|
||||
public void failoverEvent(FailoverEventType eventType) {
|
||||
failedOver.countDown();
|
||||
}
|
||||
});
|
||||
Thread t;
|
||||
|
||||
{
|
||||
final MapMessage message = createLargeMessage();
|
||||
|
||||
t = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
producer.send(message);
|
||||
session.commit();
|
||||
} catch (JMSException expected) {
|
||||
expected.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
t.start();
|
||||
|
||||
// I'm trying to simulate the following race here:
|
||||
// The message is syncing while the client is already sending the body of the message
|
||||
|
||||
Assert.assertTrue(flagArrived.await(10, TimeUnit.SECONDS));
|
||||
|
||||
startBackup();
|
||||
|
||||
waitForRemoteBackup(connection.getSessionFactory(), 30);
|
||||
|
||||
flagWait.countDown();
|
||||
|
||||
t.join(5000);
|
||||
|
||||
log.debug("Thread joined");
|
||||
|
||||
Assert.assertFalse(t.isAlive());
|
||||
|
||||
liveServer.fail(true);
|
||||
|
||||
Assert.assertTrue(failedOver.await(10, TimeUnit.SECONDS));
|
||||
|
||||
{
|
||||
MessageConsumer consumer = session.createConsumer(queue);
|
||||
|
||||
connection.start();
|
||||
|
||||
MapMessage message = (MapMessage) consumer.receive(5000);
|
||||
|
||||
Assert.assertNotNull(message);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Assert.assertEquals(1024 * 1024, message.getBytes("test" + i).length);
|
||||
}
|
||||
|
||||
session.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public static void syncLargeMessage() {
|
||||
try {
|
||||
flagArrived.countDown();
|
||||
flagWait.await(10, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private MapMessage createLargeMessage() throws JMSException {
|
||||
MapMessage message = session.createMapMessage();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
message.setBytes("test" + i, new byte[1024 * 1024]);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.ReplicatedBackupUtils;
|
||||
import org.apache.activemq.artemis.tests.util.TransportConfigurationUtils;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ReplicationBackupTest extends ActiveMQTestBase {
|
||||
|
||||
private static final CountDownLatch ruleFired = new CountDownLatch(1);
|
||||
private ActiveMQServer backupServer;
|
||||
private ActiveMQServer liveServer;
|
||||
|
||||
/*
|
||||
* simple test to induce a potential race condition where the server's acceptors are active, but the server's
|
||||
* state != STARTED
|
||||
*/
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "prevent backup annoucement",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.SharedNothingLiveActivation",
|
||||
targetMethod = "run",
|
||||
targetLocation = "AT EXIT",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ReplicationBackupTest.breakIt();")})
|
||||
public void testReplicatedBackupAnnouncement() throws Exception {
|
||||
TransportConfiguration liveConnector = TransportConfigurationUtils.getNettyConnector(true, 0);
|
||||
TransportConfiguration liveAcceptor = TransportConfigurationUtils.getNettyAcceptor(true, 0);
|
||||
TransportConfiguration backupConnector = TransportConfigurationUtils.getNettyConnector(false, 0);
|
||||
TransportConfiguration backupAcceptor = TransportConfigurationUtils.getNettyAcceptor(false, 0);
|
||||
|
||||
Configuration backupConfig = createDefaultInVMConfig().setBindingsDirectory(getBindingsDir(0, true)).setJournalDirectory(getJournalDir(0, true)).setPagingDirectory(getPageDir(0, true)).setLargeMessagesDirectory(getLargeMessagesDir(0, true));
|
||||
|
||||
Configuration liveConfig = createDefaultInVMConfig();
|
||||
|
||||
ReplicatedBackupUtils.configureReplicationPair(backupConfig, backupConnector, backupAcceptor, liveConfig, liveConnector, liveAcceptor);
|
||||
|
||||
liveServer = createServer(liveConfig);
|
||||
|
||||
// start the live server in a new thread so we can start the backup simultaneously to induce a potential race
|
||||
Thread startThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
liveServer.start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
startThread.start();
|
||||
|
||||
ruleFired.await();
|
||||
|
||||
backupServer = createServer(backupConfig);
|
||||
backupServer.start();
|
||||
ActiveMQTestBase.waitForRemoteBackup(null, 3, true, backupServer);
|
||||
}
|
||||
|
||||
public static void breakIt() {
|
||||
ruleFired.countDown();
|
||||
try {
|
||||
/* before the fix this sleep would put the "live" server into a state where the acceptors were started
|
||||
* but the server's state != STARTED which would cause the backup to fail to announce
|
||||
*/
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.core.config.ScaleDownConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.ha.LiveOnlyPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
|
||||
import org.apache.activemq.artemis.tests.integration.cluster.distribution.ClusterTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ScaleDownFailoverTest extends ClusterTestBase {
|
||||
private static final Logger log = Logger.getLogger(ScaleDownFailoverTest.class);
|
||||
|
||||
protected static int stopCount = 0;
|
||||
private static ActiveMQServer[] staticServers;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
stopCount = 0;
|
||||
setupLiveServer(0, isFileStorage(), HAType.SharedNothingReplication, isNetty(), true);
|
||||
setupLiveServer(1, isFileStorage(), HAType.SharedNothingReplication, isNetty(), true);
|
||||
setupLiveServer(2, isFileStorage(), HAType.SharedNothingReplication, isNetty(), true);
|
||||
ScaleDownConfiguration scaleDownConfiguration = new ScaleDownConfiguration();
|
||||
ScaleDownConfiguration scaleDownConfiguration2 = new ScaleDownConfiguration();
|
||||
scaleDownConfiguration2.setEnabled(false);
|
||||
ScaleDownConfiguration scaleDownConfiguration3 = new ScaleDownConfiguration();
|
||||
scaleDownConfiguration3.setEnabled(false);
|
||||
((LiveOnlyPolicyConfiguration) servers[0].getConfiguration().getHAPolicyConfiguration()).setScaleDownConfiguration(scaleDownConfiguration);
|
||||
((LiveOnlyPolicyConfiguration) servers[1].getConfiguration().getHAPolicyConfiguration()).setScaleDownConfiguration(scaleDownConfiguration2);
|
||||
((LiveOnlyPolicyConfiguration) servers[2].getConfiguration().getHAPolicyConfiguration()).setScaleDownConfiguration(scaleDownConfiguration3);
|
||||
if (isGrouped()) {
|
||||
scaleDownConfiguration.setGroupName("bill");
|
||||
scaleDownConfiguration2.setGroupName("bill");
|
||||
scaleDownConfiguration3.setGroupName("bill");
|
||||
}
|
||||
staticServers = servers;
|
||||
setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 0, 1, 2);
|
||||
setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 1, 0, 2);
|
||||
setupClusterConnection("cluster2", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 2, 0, 1);
|
||||
scaleDownConfiguration.getConnectors().addAll(servers[0].getConfiguration().getClusterConfigurations().iterator().next().getStaticConnectors());
|
||||
scaleDownConfiguration2.getConnectors().addAll(servers[1].getConfiguration().getClusterConfigurations().iterator().next().getStaticConnectors());
|
||||
scaleDownConfiguration3.getConnectors().addAll(servers[2].getConfiguration().getClusterConfigurations().iterator().next().getStaticConnectors());
|
||||
|
||||
startServers(0, 1, 2);
|
||||
setupSessionFactory(0, isNetty());
|
||||
setupSessionFactory(1, isNetty());
|
||||
setupSessionFactory(2, isNetty());
|
||||
}
|
||||
|
||||
protected boolean isNetty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isGrouped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRule(
|
||||
name = "blow-up",
|
||||
targetClass = "org.apache.activemq.artemis.api.core.client.ServerLocator",
|
||||
targetMethod = "createSessionFactory(org.apache.activemq.artemis.api.core.TransportConfiguration, int, boolean)",
|
||||
isInterface = true,
|
||||
targetLocation = "ENTRY",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.ScaleDownFailoverTest.fail($1);")
|
||||
public void testScaleDownWhenFirstServerFails() throws Exception {
|
||||
final int TEST_SIZE = 2;
|
||||
final String addressName = "testAddress";
|
||||
final String queueName1 = "testQueue1";
|
||||
final String queueName2 = "testQueue2";
|
||||
|
||||
// create 2 queues on each node mapped to the same address
|
||||
createQueue(0, addressName, queueName1, null, false);
|
||||
createQueue(0, addressName, queueName2, null, false);
|
||||
createQueue(1, addressName, queueName1, null, false);
|
||||
createQueue(1, addressName, queueName2, null, false);
|
||||
createQueue(2, addressName, queueName1, null, false);
|
||||
createQueue(2, addressName, queueName2, null, false);
|
||||
|
||||
// send messages to node 0
|
||||
send(0, addressName, TEST_SIZE, false, null);
|
||||
|
||||
// consume a message from node 0
|
||||
addConsumer(0, 0, queueName2, null);
|
||||
ClientMessage clientMessage = consumers[0].getConsumer().receive(250);
|
||||
Assert.assertNotNull(clientMessage);
|
||||
clientMessage.acknowledge();
|
||||
removeConsumer(0);
|
||||
|
||||
servers[0].stop();
|
||||
|
||||
// verify that at least one server stopped
|
||||
Assert.assertTrue(!servers[1].isStarted() || !servers[2].isStarted());
|
||||
|
||||
int remainingServer;
|
||||
if (servers[1].isStarted())
|
||||
remainingServer = 1;
|
||||
else
|
||||
remainingServer = 2;
|
||||
|
||||
// get the 2 messages from queue 1
|
||||
addConsumer(0, remainingServer, queueName1, null);
|
||||
clientMessage = consumers[0].getConsumer().receive(250);
|
||||
Assert.assertNotNull(clientMessage);
|
||||
clientMessage.acknowledge();
|
||||
clientMessage = consumers[0].getConsumer().receive(250);
|
||||
Assert.assertNotNull(clientMessage);
|
||||
clientMessage.acknowledge();
|
||||
|
||||
// ensure there are no more messages on queue 1
|
||||
clientMessage = consumers[0].getConsumer().receive(250);
|
||||
Assert.assertNull(clientMessage);
|
||||
removeConsumer(0);
|
||||
|
||||
// get the 1 message from queue 2
|
||||
addConsumer(0, remainingServer, queueName2, null);
|
||||
clientMessage = consumers[0].getConsumer().receive(250);
|
||||
Assert.assertNotNull(clientMessage);
|
||||
clientMessage.acknowledge();
|
||||
|
||||
// ensure there are no more messages on queue 1
|
||||
clientMessage = consumers[0].getConsumer().receive(250);
|
||||
Assert.assertNull(clientMessage);
|
||||
removeConsumer(0);
|
||||
}
|
||||
|
||||
public static void fail(TransportConfiguration tc) {
|
||||
// only kill one server
|
||||
if (stopCount == 0) {
|
||||
try {
|
||||
for (ActiveMQServer activeMQServer : staticServers) {
|
||||
if (activeMQServer != null) {
|
||||
for (TransportConfiguration transportConfiguration : activeMQServer.getConfiguration().getAcceptorConfigurations()) {
|
||||
if (transportConfiguration.getParams().get(TransportConstants.PORT_PROP_NAME).equals(tc.getParams().get(TransportConstants.PORT_PROP_NAME))) {
|
||||
activeMQServer.stop();
|
||||
stopCount++;
|
||||
log.debug("Stopping server listening at: " + tc.getParams().get(TransportConstants.PORT_PROP_NAME));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.core.config.ScaleDownConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.ha.LiveOnlyPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
|
||||
import org.apache.activemq.artemis.tests.integration.cluster.distribution.ClusterTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class ScaleDownFailureTest extends ClusterTestBase {
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
setupLiveServer(0, isFileStorage(), HAType.SharedNothingReplication, isNetty(), true);
|
||||
setupLiveServer(1, isFileStorage(), HAType.SharedNothingReplication, isNetty(), true);
|
||||
if (isGrouped()) {
|
||||
ScaleDownConfiguration scaleDownConfiguration = new ScaleDownConfiguration();
|
||||
scaleDownConfiguration.setGroupName("bill");
|
||||
((LiveOnlyPolicyConfiguration) servers[0].getConfiguration().getHAPolicyConfiguration()).setScaleDownConfiguration(scaleDownConfiguration);
|
||||
((LiveOnlyPolicyConfiguration) servers[1].getConfiguration().getHAPolicyConfiguration()).setScaleDownConfiguration(scaleDownConfiguration);
|
||||
}
|
||||
setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 0, 1);
|
||||
setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 1, 0);
|
||||
startServers(0, 1);
|
||||
setupSessionFactory(0, isNetty());
|
||||
setupSessionFactory(1, isNetty());
|
||||
}
|
||||
|
||||
protected boolean isNetty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isGrouped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
@BMRule(
|
||||
name = "blow-up",
|
||||
targetClass = "org.apache.activemq.artemis.api.core.client.ServerLocator",
|
||||
targetMethod = "createSessionFactory(org.apache.activemq.artemis.api.core.TransportConfiguration, int, boolean)",
|
||||
isInterface = true,
|
||||
targetLocation = "ENTRY",
|
||||
action = "throw new Exception()")
|
||||
public void testScaleDownWhenRemoteServerIsUnavailable() throws Exception {
|
||||
final int TEST_SIZE = 1;
|
||||
final String addressName = "testAddress";
|
||||
final String queueName1 = "testQueue1";
|
||||
final String queueName2 = "testQueue2";
|
||||
|
||||
// create 2 queues on each node mapped to the same address
|
||||
createQueue(0, addressName, queueName1, null, false);
|
||||
createQueue(0, addressName, queueName2, null, false);
|
||||
createQueue(1, addressName, queueName1, null, false);
|
||||
createQueue(1, addressName, queueName2, null, false);
|
||||
|
||||
// send messages to node 0
|
||||
send(0, addressName, TEST_SIZE, false, null);
|
||||
|
||||
// consume a message from node 0
|
||||
addConsumer(0, 0, queueName2, null, false);
|
||||
ClientMessage clientMessage = consumers[0].getConsumer().receive();
|
||||
Assert.assertNotNull(clientMessage);
|
||||
clientMessage.acknowledge();
|
||||
consumers[0].getSession().commit();
|
||||
removeConsumer(0);
|
||||
|
||||
servers[0].stop();
|
||||
|
||||
addConsumer(0, 1, queueName1, null);
|
||||
clientMessage = consumers[0].getConsumer().receive(250);
|
||||
Assert.assertNull(clientMessage);
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
public class ScaleDownGroupedFailoverTest extends ScaleDownFailoverTest {
|
||||
|
||||
@Override
|
||||
protected boolean isGrouped() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
public class ScaleDownGroupedFailureTest extends ScaleDownFailureTest {
|
||||
|
||||
@Override
|
||||
protected boolean isGrouped() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.ha.SharedStoreMasterPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.ha.SharedStoreSlavePolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.registry.JndiBindingRegistry;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServers;
|
||||
import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
|
||||
import org.apache.activemq.artemis.tests.unit.util.InVMNamingContext;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This test validates a deadlock identified by https://bugzilla.redhat.com/show_bug.cgi?id=959616
|
||||
*/
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class StartStopDeadlockTest extends ActiveMQTestBase {
|
||||
private static final Logger log = Logger.getLogger(StartStopDeadlockTest.class);
|
||||
|
||||
private static void debugLog(String message) {
|
||||
log.debug(message);
|
||||
}
|
||||
|
||||
/*
|
||||
* simple test to make sure connect still works with some network latency built into netty
|
||||
* */
|
||||
@Test
|
||||
@BMRules(
|
||||
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Server.start wait-init",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl",
|
||||
targetMethod = "initialisePart2",
|
||||
targetLocation = "ENTRY",
|
||||
condition = "incrementCounter(\"server-Init\") == 2",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.StartStopDeadlockTest.debugLog(\"server backup init\"), waitFor(\"start-init\")"),
|
||||
@BMRule(
|
||||
name = "JMSServer.stop wait-init",
|
||||
targetClass = "org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl",
|
||||
targetMethod = "stop",
|
||||
targetLocation = "ENTRY",
|
||||
action = "signalWake(\"start-init\", true)"),
|
||||
@BMRule(
|
||||
name = "StartStopDeadlockTest tearDown",
|
||||
targetClass = "org.apache.activemq.artemis.tests.extras.byteman.StartStopDeadlockTest",
|
||||
targetMethod = "tearDown",
|
||||
targetLocation = "ENTRY",
|
||||
action = "deleteCounter(\"server-Init\")")})
|
||||
public void testDeadlock() throws Exception {
|
||||
|
||||
// A live server that will always be crashed
|
||||
Configuration confLive = createDefaultNettyConfig().setHAPolicyConfiguration(new SharedStoreMasterPolicyConfiguration());
|
||||
final ActiveMQServer serverLive = addServer(ActiveMQServers.newActiveMQServer(confLive));
|
||||
serverLive.start();
|
||||
|
||||
// A backup that will be waiting to be activated
|
||||
Configuration config = createDefaultNettyConfig().setHAPolicyConfiguration(new SharedStoreSlavePolicyConfiguration());
|
||||
|
||||
final ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(config, true));
|
||||
|
||||
final JMSServerManagerImpl jmsServer = new JMSServerManagerImpl(server);
|
||||
final InVMNamingContext context = new InVMNamingContext();
|
||||
jmsServer.setRegistry(new JndiBindingRegistry(context));
|
||||
|
||||
jmsServer.start();
|
||||
|
||||
final AtomicInteger errors = new AtomicInteger(0);
|
||||
final CountDownLatch align = new CountDownLatch(2);
|
||||
final CountDownLatch startLatch = new CountDownLatch(1);
|
||||
|
||||
Thread tCrasher = new Thread("tStart") {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
align.countDown();
|
||||
startLatch.await();
|
||||
log.debug("Crashing....");
|
||||
serverLive.fail(true);
|
||||
} catch (Exception e) {
|
||||
errors.incrementAndGet();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread tStop = new Thread("tStop") {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
align.countDown();
|
||||
startLatch.await();
|
||||
jmsServer.stop();
|
||||
} catch (Exception e) {
|
||||
errors.incrementAndGet();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tCrasher.start();
|
||||
tStop.start();
|
||||
align.await();
|
||||
startLatch.countDown();
|
||||
|
||||
tCrasher.join();
|
||||
tStop.join();
|
||||
|
||||
assertEquals(0, errors.get());
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.api.core.management.CoreNotificationType;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.protocol.stomp.StompProtocolManagerFactory;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.management.Notification;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class StompInternalStateTest extends ActiveMQTestBase {
|
||||
|
||||
private static final String STOMP_QUEUE_NAME = "StompTestQueue";
|
||||
|
||||
private String resultTestStompProtocolManagerLeak = null;
|
||||
|
||||
protected ActiveMQServer server = null;
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "StompProtocolManager Leak Server Rule",
|
||||
targetClass = "org.apache.activemq.artemis.core.protocol.stomp.StompProtocolManager",
|
||||
targetMethod = "onNotification(org.apache.activemq.artemis.core.server.management.Notification)",
|
||||
targetLocation = "EXIT",
|
||||
helper = "org.apache.activemq.artemis.tests.extras.byteman.StompInternalStateTest",
|
||||
action = "verifyBindingAddRemove($1, $0.destinations)")})
|
||||
public void testStompProtocolManagerLeak() throws Exception {
|
||||
ClientSession session = null;
|
||||
try {
|
||||
assertNull(resultTestStompProtocolManagerLeak);
|
||||
ServerLocator locator = createNettyNonHALocator();
|
||||
ClientSessionFactory factory = createSessionFactory(locator);
|
||||
session = factory.createSession();
|
||||
session.createQueue(new QueueConfiguration(STOMP_QUEUE_NAME).setDurable(false).setTemporary(true));
|
||||
session.deleteQueue(STOMP_QUEUE_NAME);
|
||||
|
||||
assertNull(resultTestStompProtocolManagerLeak);
|
||||
} finally {
|
||||
if (session != null) {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Configuration createDefaultConfig(final boolean netty) throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(TransportConstants.PROTOCOLS_PROP_NAME, StompProtocolManagerFactory.STOMP_PROTOCOL_NAME);
|
||||
params.put(TransportConstants.PORT_PROP_NAME, TransportConstants.DEFAULT_STOMP_PORT);
|
||||
params.put(TransportConstants.STOMP_CONSUMERS_CREDIT, "-1");
|
||||
TransportConfiguration stompTransport = new TransportConfiguration(NettyAcceptorFactory.class.getName(), params);
|
||||
|
||||
Configuration config = super.createDefaultConfig(netty).setPersistenceEnabled(false).addAcceptorConfiguration(stompTransport);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void verifyBindingAddRemove(Notification noti, Object obj) {
|
||||
Set<String> destinations = (Set<String>) obj;
|
||||
if (noti.getType() == CoreNotificationType.BINDING_ADDED) {
|
||||
if (!destinations.contains(STOMP_QUEUE_NAME)) {
|
||||
resultTestStompProtocolManagerLeak += "didn't save the queue when binding added " + destinations;
|
||||
}
|
||||
} else if (noti.getType() == CoreNotificationType.BINDING_REMOVED) {
|
||||
if (destinations.contains(STOMP_QUEUE_NAME)) {
|
||||
resultTestStompProtocolManagerLeak = "didn't remove the queue when binding removed " + destinations;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
server = createServer(createDefaultNettyConfig());
|
||||
server.start();
|
||||
}
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.byteman;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.XAConnection;
|
||||
import javax.jms.XASession;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import javax.transaction.xa.Xid;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class TimeoutXATest extends ActiveMQTestBase {
|
||||
|
||||
protected ActiveMQServer server = null;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
server = createServer(createDefaultNettyConfig());
|
||||
server.getConfiguration().setTransactionTimeout(1000);
|
||||
server.getConfiguration().setTransactionTimeoutScanPeriod(1100);
|
||||
server.getConfiguration().setJournalSyncNonTransactional(false);
|
||||
server.start();
|
||||
server.createQueue(new QueueConfiguration("Queue1").setRoutingType(RoutingType.ANYCAST));
|
||||
|
||||
removingTXEntered0 = new CountDownLatch(1);
|
||||
removingTXAwait0 = new CountDownLatch(1);
|
||||
removingTXEntered1 = new CountDownLatch(1);
|
||||
removingTXAwait1 = new CountDownLatch(1);
|
||||
entered = 0;
|
||||
|
||||
enteredRollback = 0;
|
||||
enteredRollbackLatch = new CountDownLatch(1);
|
||||
waitingRollbackLatch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
static int entered;
|
||||
static CountDownLatch removingTXEntered0;
|
||||
static CountDownLatch removingTXAwait0;
|
||||
static CountDownLatch removingTXEntered1;
|
||||
static CountDownLatch removingTXAwait1;
|
||||
|
||||
static int enteredRollback;
|
||||
static CountDownLatch enteredRollbackLatch;
|
||||
static CountDownLatch waitingRollbackLatch;
|
||||
|
||||
@Test
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "removing TX",
|
||||
targetClass = "org.apache.activemq.artemis.core.transaction.impl.ResourceManagerImpl",
|
||||
targetMethod = "removeTransaction(javax.transaction.xa.Xid)",
|
||||
targetLocation = "ENTRY",
|
||||
helper = "org.apache.activemq.artemis.tests.extras.byteman.TimeoutXATest",
|
||||
action = "removingTX()"),
|
||||
@BMRule(
|
||||
name = "afterRollback TX",
|
||||
targetClass = "org.apache.activemq.artemis.core.transaction.impl.TransactionImpl",
|
||||
targetMethod = "afterRollback",
|
||||
targetLocation = "ENTRY",
|
||||
helper = "org.apache.activemq.artemis.tests.extras.byteman.TimeoutXATest",
|
||||
action = "afterRollback()")})
|
||||
public void testTimeoutOnTX2() throws Exception {
|
||||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
|
||||
XAConnection connection = connectionFactory.createXAConnection();
|
||||
|
||||
Connection connction2 = connectionFactory.createConnection();
|
||||
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
|
||||
Queue queue = session.createQueue("Queue1");
|
||||
|
||||
MessageProducer producer = session.createProducer(queue);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
producer.send(session.createTextMessage("hello " + 1));
|
||||
}
|
||||
|
||||
session.commit();
|
||||
|
||||
final XASession xaSession = connection.createXASession();
|
||||
final Xid xid = newXID();
|
||||
|
||||
xaSession.getXAResource().start(xid, XAResource.TMNOFLAGS);
|
||||
MessageConsumer consumer = xaSession.createConsumer(queue);
|
||||
connection.start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Assert.assertNotNull(consumer.receive(5000));
|
||||
}
|
||||
xaSession.getXAResource().end(xid, XAResource.TMSUCCESS);
|
||||
|
||||
final CountDownLatch latchStore = new CountDownLatch(1000);
|
||||
|
||||
Thread storingThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
latchStore.countDown();
|
||||
server.getStorageManager().storeDuplicateID(SimpleString.toSimpleString("crebis"), new byte[]{1}, server.getStorageManager().generateID());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
removingTXEntered0.await();
|
||||
|
||||
Thread t = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
xaSession.getXAResource().rollback(xid);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
t.start();
|
||||
|
||||
removingTXEntered1.await();
|
||||
|
||||
storingThread.start();
|
||||
latchStore.await();
|
||||
|
||||
removingTXAwait1.countDown();
|
||||
|
||||
Thread.sleep(1000);
|
||||
removingTXAwait0.countDown();
|
||||
|
||||
Assert.assertTrue(enteredRollbackLatch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
waitingRollbackLatch.countDown();
|
||||
|
||||
t.join();
|
||||
|
||||
consumer.close();
|
||||
|
||||
consumer = session.createConsumer(queue);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Assert.assertNotNull(consumer.receive(5000));
|
||||
}
|
||||
Assert.assertNull(consumer.receiveNoWait());
|
||||
|
||||
connection.close();
|
||||
connction2.close();
|
||||
|
||||
}
|
||||
|
||||
public void afterRollback() {
|
||||
if (enteredRollback++ == 0) {
|
||||
enteredRollbackLatch.countDown();
|
||||
try {
|
||||
waitingRollbackLatch.await();
|
||||
} catch (Throwable e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void removingTX() {
|
||||
int xent = entered++;
|
||||
|
||||
if (xent == 0) {
|
||||
removingTXEntered0.countDown();
|
||||
try {
|
||||
removingTXAwait0.await();
|
||||
} catch (Throwable ignored) {
|
||||
ignored.printStackTrace();
|
||||
}
|
||||
} else if (xent == 1) {
|
||||
removingTXEntered1.countDown();
|
||||
try {
|
||||
removingTXAwait1.await();
|
||||
} catch (Throwable ignored) {
|
||||
ignored.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman.critical.analyzer;
|
||||
|
||||
import javax.jms.DeliveryMode;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.server.JournalType;
|
||||
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
|
||||
import org.apache.activemq.artemis.tests.util.JMSTestBase;
|
||||
import org.apache.activemq.artemis.tests.util.Wait;
|
||||
import org.apache.activemq.artemis.utils.critical.CriticalAnalyzerPolicy;
|
||||
import org.junit.Before;
|
||||
|
||||
public abstract class CriticalAnalyzerFaultInjectionTestBase extends JMSTestBase {
|
||||
|
||||
// Critical Analyzer Settings
|
||||
private static long CHECK_PERIOD = 100;
|
||||
private static long TIMEOUT = 3000;
|
||||
|
||||
protected SimpleString address = SimpleString.toSimpleString("faultInjectionTestAddress");
|
||||
|
||||
private Thread t;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
server.addAddressInfo(new AddressInfo(address, RoutingType.ANYCAST));
|
||||
server.createQueue(new QueueConfiguration(address).setRoutingType(RoutingType.ANYCAST));
|
||||
conn = nettyCf.createConnection();
|
||||
}
|
||||
|
||||
/*
|
||||
Checks every 100ms timesout after 3000ms. Test should wait no longer than 3100s + Shutdown time.
|
||||
*/
|
||||
@Override
|
||||
protected Configuration createDefaultConfig(boolean netty) throws Exception {
|
||||
return super.createDefaultConfig(netty).setCriticalAnalyzerPolicy(CriticalAnalyzerPolicy.SHUTDOWN).setCriticalAnalyzer(true).setCriticalAnalyzerCheckPeriod(CHECK_PERIOD).setCriticalAnalyzerTimeout(TIMEOUT).setJournalType(JournalType.NIO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usePersistence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void testSendDurableMessage() throws Exception {
|
||||
try {
|
||||
t = new Thread(() -> {
|
||||
try {
|
||||
Session s = conn.createSession(true, Session.SESSION_TRANSACTED);
|
||||
|
||||
Queue jmsQueue = s.createQueue(address.toString());
|
||||
MessageProducer p = s.createProducer(jmsQueue);
|
||||
p.setDeliveryMode(DeliveryMode.PERSISTENT);
|
||||
conn.start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
p.send(s.createTextMessage("payload"));
|
||||
}
|
||||
s.commit();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
Wait.assertFalse(server::isStarted);
|
||||
} finally {
|
||||
t.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman.critical.analyzer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.apache.activemq.artemis.core.persistence.impl.journal.AbstractJournalStorageManager;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class DeadlockStorageManagerTest extends CriticalAnalyzerFaultInjectionTestBase {
|
||||
|
||||
private static Thread lockT;
|
||||
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Deadlock on Storage Manager",
|
||||
targetClass = "org.apache.activemq.artemis.core.persistence.impl.journal.AbstractJournalStorageManager",
|
||||
targetMethod = "commit",
|
||||
targetLocation = "ENTRY",
|
||||
condition = "!flagged(\"testDeadlockOnStorageManager\")",
|
||||
action = "org.apache.activemq.artemis.tests.extras.byteman.critical.analyzer.DeadlockStorageManagerTest.acquireStorageManagerLock($0);"),
|
||||
@BMRule(
|
||||
name = "Release Suspended Thread during Server Shutdown", // Releases wakes up suspended threads to allow shutdown to complete
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl",
|
||||
targetMethod = "stop",
|
||||
targetLocation = "ENTRY",
|
||||
action = "flag(\"testDeadlockOnStorageManager\"); org.apache.activemq.artemis.tests.extras.byteman.critical.analyzer.DeadlockStorageManagerTest.releaseStorageManagerLock()" )
|
||||
})
|
||||
@Test(timeout = 60000)
|
||||
public void testDeadlockOnStorageManager() throws Exception {
|
||||
testSendDurableMessage();
|
||||
}
|
||||
|
||||
public static void acquireStorageManagerLock(final Object o) throws Exception {
|
||||
// We're attempting to cause a deadlock on the readlock. This means we need to grab the write lock
|
||||
// in a separate thread.
|
||||
if (lockT == null) {
|
||||
lockT = new Thread(() -> {
|
||||
try {
|
||||
Field field = AbstractJournalStorageManager.class.getDeclaredField("storageManagerLock");
|
||||
field.setAccessible(true);
|
||||
ReentrantReadWriteLock lock = ((ReentrantReadWriteLock) field.get(o));
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException ie) {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
});
|
||||
lockT.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void releaseStorageManagerLock() throws NoSuchFieldException, IllegalAccessException {
|
||||
lockT.interrupt();
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman.critical.analyzer;
|
||||
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class DeadlockedQueueTest extends CriticalAnalyzerFaultInjectionTestBase {
|
||||
|
||||
@BMRules(
|
||||
rules = {
|
||||
@BMRule(
|
||||
name = "Deadlock during Queue Delivery",
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.QueueImpl",
|
||||
targetMethod = "deliver",
|
||||
targetLocation = "AFTER SYNCHRONIZE",
|
||||
condition = "!flagged(\"testDeadlockOnQueue\")",
|
||||
action = "waitFor(\"testDeadlockOnQueue\")"),
|
||||
@BMRule(
|
||||
name = "Release Suspended Thread during Server Shutdown", // Releases wakes up suspended threads to allow shutdown to complete
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl",
|
||||
targetMethod = "stop",
|
||||
targetLocation = "ENTRY",
|
||||
action = "flag(\"testDeadlockOnQueue\"); signalWake(\"testDeadlockOnQueue\")")
|
||||
})
|
||||
@Test(timeout = 60000)
|
||||
public void testDeadlockOnQueue() throws Exception {
|
||||
testSendDurableMessage();
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.byteman.critical.analyzer;
|
||||
|
||||
import javax.jms.DeliveryMode;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
|
||||
import org.jboss.byteman.contrib.bmunit.BMRule;
|
||||
import org.jboss.byteman.contrib.bmunit.BMRules;
|
||||
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(BMUnitRunner.class)
|
||||
public class FileSystemSyncBlockedTest extends CriticalAnalyzerFaultInjectionTestBase {
|
||||
private static final Logger log = Logger.getLogger(FileSystemSyncBlockedTest.class);
|
||||
|
||||
@BMRules(rules = {
|
||||
@BMRule(
|
||||
name = "Simulate Slow Disk Sync",
|
||||
targetClass = "org.apache.activemq.artemis.core.io.nio.NIOSequentialFile",
|
||||
targetMethod = "sync",
|
||||
targetLocation = "ENTRY",
|
||||
condition = "!flagged(\"testSlowDiskSync\")", // Once the server shutdowns we stop applying this rule.
|
||||
action = "waitFor(\"testSlowDiskSync\")"),
|
||||
@BMRule(
|
||||
// We ensure that no more
|
||||
name = "Release Suspended Thread during Server Shutdown", // Releases wakes up suspended threads to allow shutdown to complete
|
||||
targetClass = "org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl",
|
||||
targetMethod = "stop",
|
||||
targetLocation = "ENTRY",
|
||||
action = "flag(\"testSlowDiskSync\"); signalWake(\"testSlowDiskSync\")")})
|
||||
@Test(timeout = 60000)
|
||||
public void testSlowDiskSync() throws Exception {
|
||||
testSendDurableMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyFiles() throws Exception {
|
||||
Session s = conn.createSession(true, Session.SESSION_TRANSACTED);
|
||||
|
||||
Queue jmsQueue = s.createQueue(address.toString());
|
||||
MessageProducer p = s.createProducer(jmsQueue);
|
||||
p.setDeliveryMode(DeliveryMode.PERSISTENT);
|
||||
conn.start();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
p.send(s.createTextMessage("payload"));
|
||||
server.getStorageManager().getMessageJournal().forceMoveNextFile();
|
||||
}
|
||||
s.commit();
|
||||
|
||||
// if you have more than 100 components, then you have a leak!
|
||||
Assert.assertTrue(server.getStorageManager().getJournalSequentialFileFactory().getCriticalAnalyzer().getNumberOfComponents() < 10);
|
||||
log.debug("Number of components:" + server.getStorageManager().getJournalSequentialFileFactory().getCriticalAnalyzer().getNumberOfComponents());
|
||||
|
||||
}
|
||||
}
|
|
@ -1,488 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.jms.bridge;
|
||||
|
||||
import javax.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.Queue;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.TextMessage;
|
||||
import javax.jms.Topic;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
import javax.transaction.TransactionManager;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.arjuna.ats.arjuna.coordinator.TransactionReaper;
|
||||
import com.arjuna.ats.arjuna.coordinator.TxControl;
|
||||
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.management.AddressControl;
|
||||
import org.apache.activemq.artemis.api.core.management.QueueControl;
|
||||
import org.apache.activemq.artemis.api.core.management.ResourceNames;
|
||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServers;
|
||||
import org.apache.activemq.artemis.core.server.management.ManagementService;
|
||||
import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory;
|
||||
import org.apache.activemq.artemis.jms.bridge.DestinationFactory;
|
||||
import org.apache.activemq.artemis.jms.bridge.QualityOfServiceMode;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQMessage;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
||||
public abstract class BridgeTestBase extends ActiveMQTestBase {
|
||||
|
||||
protected ConnectionFactoryFactory cff0, cff1;
|
||||
|
||||
protected ConnectionFactoryFactory cff0xa, cff1xa;
|
||||
|
||||
protected ConnectionFactory cf0, cf1;
|
||||
|
||||
protected XAConnectionFactory cf0xa, cf1xa;
|
||||
|
||||
protected DestinationFactory sourceQueueFactory;
|
||||
protected DestinationFactory targetQueueFactory;
|
||||
protected DestinationFactory localTargetQueueFactory;
|
||||
protected DestinationFactory sourceTopicFactory;
|
||||
|
||||
protected Queue sourceQueue, targetQueue, localTargetQueue;
|
||||
|
||||
protected Topic sourceTopic;
|
||||
|
||||
protected ActiveMQServer server0;
|
||||
|
||||
protected ActiveMQServer server1;
|
||||
|
||||
protected HashMap<String, Object> params1;
|
||||
|
||||
protected ConnectionFactoryFactory cff0LowProducerWindow;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
// Start the servers
|
||||
Configuration conf0 = createBasicConfig().setJournalDirectory(getJournalDir(0, false)).setBindingsDirectory(getBindingsDir(0, false)).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY));
|
||||
|
||||
server0 = addServer(ActiveMQServers.newActiveMQServer(conf0, false));
|
||||
server0.start();
|
||||
|
||||
params1 = new HashMap<>();
|
||||
params1.put(TransportConstants.SERVER_ID_PROP_NAME, 1);
|
||||
|
||||
Configuration conf1 = createBasicConfig().setJournalDirectory(getJournalDir(1, false)).setBindingsDirectory(getBindingsDir(1, false)).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY, params1));
|
||||
|
||||
server1 = addServer(ActiveMQServers.newActiveMQServer(conf1, false));
|
||||
server1.start();
|
||||
|
||||
setUpAdministeredObjects();
|
||||
TxControl.enable();
|
||||
// We need a local transaction and recovery manager
|
||||
// We must start this after the remote servers have been created or it won't
|
||||
// have deleted the database and the recovery manager may attempt to recover transactions
|
||||
|
||||
}
|
||||
|
||||
protected void createQueue(final String queueName, final int index) throws Exception {
|
||||
ActiveMQServer server = server0;
|
||||
if (index == 1) {
|
||||
server = server1;
|
||||
}
|
||||
assertTrue("queue '/queue/" + queueName + "' created", server.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST)) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
checkEmpty(sourceQueue, 0);
|
||||
checkEmpty(localTargetQueue, 0);
|
||||
checkEmpty(targetQueue, 1);
|
||||
|
||||
// Check no subscriptions left lying around
|
||||
|
||||
checkNoSubscriptions(sourceTopic, 0);
|
||||
if (cff0 instanceof ActiveMQConnectionFactory) {
|
||||
((ActiveMQConnectionFactory) cff0).close();
|
||||
}
|
||||
if (cff1 instanceof ActiveMQConnectionFactory) {
|
||||
((ActiveMQConnectionFactory) cff1).close();
|
||||
}
|
||||
stopComponent(server0);
|
||||
stopComponent(server1);
|
||||
cff0 = cff1 = null;
|
||||
cff0xa = cff1xa = null;
|
||||
|
||||
cf0 = cf1 = null;
|
||||
|
||||
cf0xa = cf1xa = null;
|
||||
|
||||
sourceQueueFactory = targetQueueFactory = localTargetQueueFactory = sourceTopicFactory = null;
|
||||
|
||||
sourceQueue = targetQueue = localTargetQueue = null;
|
||||
|
||||
sourceTopic = null;
|
||||
|
||||
server0 = null;
|
||||
|
||||
server1 = null;
|
||||
|
||||
// Shutting down Arjuna threads
|
||||
TxControl.disable(true);
|
||||
|
||||
TransactionReaper.terminate(false);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected void setUpAdministeredObjects() throws Exception {
|
||||
cff0LowProducerWindow = new ConnectionFactoryFactory() {
|
||||
@Override
|
||||
public ConnectionFactory createConnectionFactory() throws Exception {
|
||||
ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY));
|
||||
|
||||
// Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection
|
||||
cf.setReconnectAttempts(0);
|
||||
cf.setBlockOnNonDurableSend(true);
|
||||
cf.setBlockOnDurableSend(true);
|
||||
cf.setCacheLargeMessagesClient(true);
|
||||
cf.setProducerWindowSize(100);
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
cff0 = new ConnectionFactoryFactory() {
|
||||
@Override
|
||||
public ConnectionFactory createConnectionFactory() throws Exception {
|
||||
ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY));
|
||||
|
||||
// Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection
|
||||
cf.setReconnectAttempts(0);
|
||||
cf.setBlockOnNonDurableSend(true);
|
||||
cf.setBlockOnDurableSend(true);
|
||||
cf.setCacheLargeMessagesClient(true);
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
cff0xa = new ConnectionFactoryFactory() {
|
||||
@Override
|
||||
public Object createConnectionFactory() throws Exception {
|
||||
ActiveMQXAConnectionFactory cf = (ActiveMQXAConnectionFactory) ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.XA_CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY));
|
||||
|
||||
// Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection
|
||||
cf.setReconnectAttempts(0);
|
||||
cf.setBlockOnNonDurableSend(true);
|
||||
cf.setBlockOnDurableSend(true);
|
||||
cf.setCacheLargeMessagesClient(true);
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
cf0 = (ConnectionFactory) cff0.createConnectionFactory();
|
||||
cf0xa = (XAConnectionFactory) cff0xa.createConnectionFactory();
|
||||
|
||||
cff1 = new ConnectionFactoryFactory() {
|
||||
|
||||
@Override
|
||||
public ConnectionFactory createConnectionFactory() throws Exception {
|
||||
ActiveMQJMSConnectionFactory cf = (ActiveMQJMSConnectionFactory) ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY, params1));
|
||||
|
||||
// Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection
|
||||
cf.setReconnectAttempts(0);
|
||||
cf.setBlockOnNonDurableSend(true);
|
||||
cf.setBlockOnDurableSend(true);
|
||||
cf.setCacheLargeMessagesClient(true);
|
||||
|
||||
return cf;
|
||||
}
|
||||
};
|
||||
|
||||
cff1xa = new ConnectionFactoryFactory() {
|
||||
|
||||
@Override
|
||||
public XAConnectionFactory createConnectionFactory() throws Exception {
|
||||
ActiveMQXAConnectionFactory cf = (ActiveMQXAConnectionFactory) ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.XA_CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY, params1));
|
||||
|
||||
// Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection
|
||||
cf.setReconnectAttempts(0);
|
||||
cf.setBlockOnNonDurableSend(true);
|
||||
cf.setBlockOnDurableSend(true);
|
||||
cf.setCacheLargeMessagesClient(true);
|
||||
|
||||
return cf;
|
||||
}
|
||||
};
|
||||
|
||||
cf1 = (ConnectionFactory) cff1.createConnectionFactory();
|
||||
cf1xa = (XAConnectionFactory) cff1xa.createConnectionFactory();
|
||||
|
||||
sourceQueueFactory = new DestinationFactory() {
|
||||
@Override
|
||||
public Destination createDestination() throws Exception {
|
||||
return ActiveMQDestination.createDestination("/queue/sourceQueue", ActiveMQDestination.TYPE.QUEUE);
|
||||
}
|
||||
};
|
||||
|
||||
sourceQueue = (Queue) sourceQueueFactory.createDestination();
|
||||
|
||||
targetQueueFactory = new DestinationFactory() {
|
||||
@Override
|
||||
public Destination createDestination() throws Exception {
|
||||
return ActiveMQDestination.createDestination("/queue/targetQueue", ActiveMQDestination.TYPE.QUEUE);
|
||||
}
|
||||
};
|
||||
|
||||
targetQueue = (Queue) targetQueueFactory.createDestination();
|
||||
|
||||
sourceTopicFactory = new DestinationFactory() {
|
||||
@Override
|
||||
public Destination createDestination() throws Exception {
|
||||
return ActiveMQDestination.createDestination("/topic/sourceTopic", ActiveMQDestination.TYPE.TOPIC);
|
||||
}
|
||||
};
|
||||
|
||||
sourceTopic = (Topic) sourceTopicFactory.createDestination();
|
||||
|
||||
localTargetQueueFactory = new DestinationFactory() {
|
||||
@Override
|
||||
public Destination createDestination() throws Exception {
|
||||
return ActiveMQDestination.createDestination("/queue/localTargetQueue", ActiveMQDestination.TYPE.QUEUE);
|
||||
}
|
||||
};
|
||||
|
||||
localTargetQueue = (Queue) localTargetQueueFactory.createDestination();
|
||||
}
|
||||
|
||||
protected void sendMessages(final ConnectionFactory cf,
|
||||
final Destination dest,
|
||||
final int start,
|
||||
final int numMessages,
|
||||
final boolean persistent,
|
||||
final boolean largeMessage) throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
MessageProducer prod = sess.createProducer(dest);
|
||||
|
||||
prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
|
||||
|
||||
for (int i = start; i < start + numMessages; i++) {
|
||||
if (largeMessage) {
|
||||
BytesMessage msg = sess.createBytesMessage();
|
||||
((ActiveMQMessage) msg).setInputStream(ActiveMQTestBase.createFakeLargeStream(1024L * 1024L));
|
||||
msg.setStringProperty("msg", "message" + i);
|
||||
prod.send(msg);
|
||||
} else {
|
||||
TextMessage tm = sess.createTextMessage("message" + i);
|
||||
prod.send(tm);
|
||||
}
|
||||
|
||||
}
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkMessagesReceived(final ConnectionFactory cf,
|
||||
final Destination dest,
|
||||
final QualityOfServiceMode qosMode,
|
||||
final int numMessages,
|
||||
final boolean longWaitForFirst,
|
||||
final boolean largeMessage) throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
conn.start();
|
||||
|
||||
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
MessageConsumer cons = sess.createConsumer(dest);
|
||||
|
||||
// Consume the messages
|
||||
|
||||
Set<String> msgs = new HashSet<>();
|
||||
|
||||
int count = 0;
|
||||
|
||||
// We always wait longer for the first one - it may take some time to arrive especially if we are
|
||||
// waiting for recovery to kick in
|
||||
while (true) {
|
||||
Message tm = cons.receive(count == 0 ? (longWaitForFirst ? 60000 : 10000) : 5000);
|
||||
|
||||
if (tm == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// log.info("Got message " + tm.getText());
|
||||
|
||||
if (largeMessage) {
|
||||
BytesMessage bmsg = (BytesMessage) tm;
|
||||
msgs.add(tm.getStringProperty("msg"));
|
||||
byte[] buffRead = new byte[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
Assert.assertEquals(1024, bmsg.readBytes(buffRead));
|
||||
}
|
||||
} else {
|
||||
msgs.add(((TextMessage) tm).getText());
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
}
|
||||
|
||||
if (qosMode == QualityOfServiceMode.ONCE_AND_ONLY_ONCE || qosMode == QualityOfServiceMode.DUPLICATES_OK) {
|
||||
// All the messages should be received
|
||||
|
||||
for (int i = 0; i < numMessages; i++) {
|
||||
Assert.assertTrue("quality=" + qosMode + ", #=" + i + ", message=" + msgs, msgs.contains("message" + i));
|
||||
}
|
||||
|
||||
// Should be no more
|
||||
if (qosMode == QualityOfServiceMode.ONCE_AND_ONLY_ONCE) {
|
||||
Assert.assertEquals(numMessages, msgs.size());
|
||||
}
|
||||
} else if (qosMode == QualityOfServiceMode.AT_MOST_ONCE) {
|
||||
// No *guarantee* that any messages will be received
|
||||
// but you still might get some depending on how/where the crash occurred
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkAllMessageReceivedInOrder(final ConnectionFactory cf,
|
||||
final Destination dest,
|
||||
final int start,
|
||||
final int numMessages,
|
||||
final boolean largeMessage) throws Exception {
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
conn.start();
|
||||
|
||||
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
MessageConsumer cons = sess.createConsumer(dest);
|
||||
|
||||
// Consume the messages
|
||||
|
||||
for (int i = 0; i < numMessages; i++) {
|
||||
Message tm = cons.receive(3000);
|
||||
|
||||
Assert.assertNotNull(tm);
|
||||
|
||||
if (largeMessage) {
|
||||
BytesMessage bmsg = (BytesMessage) tm;
|
||||
Assert.assertEquals("message" + (i + start), tm.getStringProperty("msg"));
|
||||
byte[] buffRead = new byte[1024];
|
||||
for (int j = 0; j < 1024; j++) {
|
||||
Assert.assertEquals(1024, bmsg.readBytes(buffRead));
|
||||
}
|
||||
} else {
|
||||
Assert.assertEquals("message" + (i + start), ((TextMessage) tm).getText());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkEmpty(final Queue queue, final int index) throws Exception {
|
||||
ManagementService managementService = server0.getManagementService();
|
||||
if (index == 1) {
|
||||
managementService = server1.getManagementService();
|
||||
}
|
||||
QueueControl queueControl = (QueueControl) managementService.getResource(ResourceNames.QUEUE + queue.getQueueName());
|
||||
|
||||
//server may be closed
|
||||
if (queueControl != null) {
|
||||
queueControl.flushExecutor();
|
||||
Long messageCount = queueControl.getMessageCount();
|
||||
|
||||
if (messageCount > 0) {
|
||||
queueControl.removeMessages(null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void checkNoSubscriptions(final Topic topic, final int index) throws Exception {
|
||||
ManagementService managementService = server0.getManagementService();
|
||||
if (index == 1) {
|
||||
managementService = server1.getManagementService();
|
||||
}
|
||||
AddressControl topicControl = (AddressControl) managementService.getResource(ResourceNames.ADDRESS + topic.getTopicName());
|
||||
if (topicControl != null) {
|
||||
Assert.assertEquals(0, topicControl.getQueueNames().length);
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeAllMessages(final String queueName, final int index) throws Exception {
|
||||
ManagementService managementService = server0.getManagementService();
|
||||
if (index == 1) {
|
||||
managementService = server1.getManagementService();
|
||||
}
|
||||
QueueControl queueControl = (QueueControl) managementService.getResource("queue." + queueName);
|
||||
if (queueControl != null) {
|
||||
queueControl.removeMessages(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected TransactionManager newTransactionManager() {
|
||||
return new TransactionManagerImple();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.jms.bridge;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.Destination;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.arjuna.ats.arjuna.coordinator.TransactionReaper;
|
||||
import com.arjuna.ats.arjuna.coordinator.TxControl;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.QueueConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.FailoverEventListener;
|
||||
import org.apache.activemq.artemis.api.core.client.FailoverEventType;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.config.ha.ReplicaPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.config.ha.ReplicatedPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServers;
|
||||
import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory;
|
||||
import org.apache.activemq.artemis.jms.bridge.DestinationFactory;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* A ClusteredBridgeTestBase
|
||||
* This class serves as a base class for jms bridge tests in
|
||||
* clustered scenarios.
|
||||
*/
|
||||
public abstract class ClusteredBridgeTestBase extends ActiveMQTestBase {
|
||||
|
||||
private static int index = 0;
|
||||
private static final int QUORUM_VOTE_WAIT_TIME_SEC = 30;
|
||||
|
||||
protected Map<String, ServerGroup> groups = new HashMap<>();
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Iterator<ServerGroup> iter = groups.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
iter.next().start();
|
||||
}
|
||||
TxControl.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
Iterator<ServerGroup> iter = groups.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
iter.next().stop();
|
||||
}
|
||||
|
||||
TxControl.disable(true);
|
||||
|
||||
TransactionReaper.terminate(false);
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
//create a live/backup pair.
|
||||
protected ServerGroup createServerGroup(String name) throws Exception {
|
||||
ServerGroup server = groups.get(name);
|
||||
if (server == null) {
|
||||
server = new ServerGroup(name, groups.size());
|
||||
server.create();
|
||||
groups.put(name, server);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
//each ServerGroup represents a live/backup pair
|
||||
protected class ServerGroup {
|
||||
|
||||
private static final int ID_OFFSET = 100;
|
||||
private String name;
|
||||
private int id;
|
||||
|
||||
private ActiveMQServer liveNode;
|
||||
private ActiveMQServer backupNode;
|
||||
|
||||
private TransportConfiguration liveConnector;
|
||||
private TransportConfiguration backupConnector;
|
||||
|
||||
private ServerLocator locator;
|
||||
private ClientSessionFactory sessionFactory;
|
||||
|
||||
/**
|
||||
* @param name - name of the group
|
||||
* @param id - id of the live (should be < 100)
|
||||
*/
|
||||
public ServerGroup(String name, int id) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void create() throws Exception {
|
||||
Map<String, Object> params0 = new HashMap<>();
|
||||
params0.put(TransportConstants.SERVER_ID_PROP_NAME, id);
|
||||
liveConnector = new TransportConfiguration(INVM_CONNECTOR_FACTORY, params0, "in-vm-live");
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(TransportConstants.SERVER_ID_PROP_NAME, id + ID_OFFSET);
|
||||
backupConnector = new TransportConfiguration(INVM_CONNECTOR_FACTORY, params, "in-vm-backup");
|
||||
|
||||
//live
|
||||
Configuration conf0 = createBasicConfig().setJournalDirectory(getJournalDir(id, false)).setBindingsDirectory(getBindingsDir(id, false)).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY, params0)).addConnectorConfiguration(liveConnector.getName(), liveConnector).setHAPolicyConfiguration(new ReplicatedPolicyConfiguration()).addClusterConfiguration(basicClusterConnectionConfig(liveConnector.getName()));
|
||||
|
||||
liveNode = addServer(ActiveMQServers.newActiveMQServer(conf0, true));
|
||||
|
||||
//backup
|
||||
ReplicaPolicyConfiguration replicaPolicyConfiguration = new ReplicaPolicyConfiguration();
|
||||
replicaPolicyConfiguration.setQuorumVoteWait(QUORUM_VOTE_WAIT_TIME_SEC);
|
||||
Configuration config = createBasicConfig().setJournalDirectory(getJournalDir(id, true)).setBindingsDirectory(getBindingsDir(id, true)).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY, params)).addConnectorConfiguration(backupConnector.getName(), backupConnector).addConnectorConfiguration(liveConnector.getName(), liveConnector).setHAPolicyConfiguration(replicaPolicyConfiguration).addClusterConfiguration(basicClusterConnectionConfig(backupConnector.getName(), liveConnector.getName()));
|
||||
|
||||
backupNode = addServer(ActiveMQServers.newActiveMQServer(config, true));
|
||||
}
|
||||
|
||||
public void start() throws Exception {
|
||||
liveNode.start();
|
||||
waitForServerToStart(liveNode);
|
||||
backupNode.start();
|
||||
waitForRemoteBackupSynchronization(backupNode);
|
||||
|
||||
locator = ActiveMQClient.createServerLocatorWithHA(liveConnector).setReconnectAttempts(15);
|
||||
sessionFactory = locator.createSessionFactory();
|
||||
}
|
||||
|
||||
public void stop() throws Exception {
|
||||
sessionFactory.close();
|
||||
locator.close();
|
||||
liveNode.stop();
|
||||
backupNode.stop();
|
||||
}
|
||||
|
||||
public void createQueue(String queueName) throws Exception {
|
||||
liveNode.createQueue(new QueueConfiguration(queueName).setRoutingType(RoutingType.ANYCAST));
|
||||
}
|
||||
|
||||
public ConnectionFactoryFactory getConnectionFactoryFactory() {
|
||||
ConnectionFactoryFactory cff = new ConnectionFactoryFactory() {
|
||||
@Override
|
||||
public ConnectionFactory createConnectionFactory() throws Exception {
|
||||
ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithHA(JMSFactoryType.XA_CF, liveConnector);
|
||||
cf.getServerLocator().setReconnectAttempts(15);
|
||||
return cf;
|
||||
}
|
||||
};
|
||||
|
||||
return cff;
|
||||
}
|
||||
|
||||
public DestinationFactory getDestinationFactory(final String queueName) {
|
||||
|
||||
DestinationFactory destFactory = new DestinationFactory() {
|
||||
@Override
|
||||
public Destination createDestination() throws Exception {
|
||||
return ActiveMQDestination.createDestination(queueName, ActiveMQDestination.TYPE.QUEUE);
|
||||
}
|
||||
};
|
||||
return destFactory;
|
||||
}
|
||||
|
||||
public void sendMessages(String queueName, int num) throws ActiveMQException {
|
||||
ClientSession session = sessionFactory.createSession();
|
||||
ClientProducer producer = session.createProducer(queueName);
|
||||
for (int i = 0; i < num; i++) {
|
||||
ClientMessage m = session.createMessage(true);
|
||||
m.putStringProperty("bridge-message", "hello " + index);
|
||||
index++;
|
||||
producer.send(m);
|
||||
}
|
||||
session.close();
|
||||
}
|
||||
|
||||
public void receiveMessages(String queueName, int num, boolean checkDup) throws ActiveMQException {
|
||||
ClientSession session = sessionFactory.createSession();
|
||||
session.start();
|
||||
ClientConsumer consumer = session.createConsumer(queueName);
|
||||
for (int i = 0; i < num; i++) {
|
||||
ClientMessage m = consumer.receive(30000);
|
||||
assertNotNull("i=" + i, m);
|
||||
assertNotNull(m.getStringProperty("bridge-message"));
|
||||
m.acknowledge();
|
||||
}
|
||||
|
||||
ClientMessage m = consumer.receive(500);
|
||||
if (checkDup) {
|
||||
assertNull(m);
|
||||
} else {
|
||||
//drain messages
|
||||
while (m != null) {
|
||||
m = consumer.receive(200);
|
||||
}
|
||||
}
|
||||
|
||||
session.close();
|
||||
}
|
||||
|
||||
public void crashLive() throws Exception {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
sessionFactory.addFailoverListener(new FailoverEventListener() {
|
||||
|
||||
@Override
|
||||
public void failoverEvent(FailoverEventType eventType) {
|
||||
if (eventType == FailoverEventType.FAILOVER_COMPLETED) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
liveNode.stop();
|
||||
|
||||
boolean ok = latch.await(10000, TimeUnit.MILLISECONDS);
|
||||
assertTrue(ok);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.jms.bridge;
|
||||
|
||||
import com.arjuna.ats.arjuna.common.Uid;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.transaction.HeuristicMixedException;
|
||||
import javax.transaction.HeuristicRollbackException;
|
||||
import javax.transaction.InvalidTransactionException;
|
||||
import javax.transaction.NotSupportedException;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.Synchronization;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAResource;
|
||||
|
||||
public class FailingTransactionManager implements TransactionManager {
|
||||
|
||||
private final TransactionManager tm;
|
||||
private int calls;
|
||||
private final int limit;
|
||||
private final AtomicInteger failures = new AtomicInteger(0);
|
||||
private final Map<Uid, FailingTransaction> transactions = Collections.synchronizedMap(new HashMap<>(10));
|
||||
|
||||
public FailingTransactionManager(TransactionManager tm, int limit) {
|
||||
this.tm = tm;
|
||||
this.calls = 0;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void begin() throws NotSupportedException, SystemException {
|
||||
tm.begin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException {
|
||||
transactions.remove(((com.arjuna.ats.jta.transaction.Transaction) tm.getTransaction()).get_uid()).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() throws IllegalStateException, SecurityException, SystemException {
|
||||
transactions.remove(((com.arjuna.ats.jta.transaction.Transaction) tm.getTransaction()).get_uid()).rollback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||
tm.setRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() throws SystemException {
|
||||
return tm.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction getTransaction() throws SystemException {
|
||||
com.arjuna.ats.jta.transaction.Transaction real = (com.arjuna.ats.jta.transaction.Transaction) tm.getTransaction();
|
||||
if (transactions.containsKey(real.get_uid())) {
|
||||
return transactions.get(real.get_uid());
|
||||
}
|
||||
FailingTransaction tx = new FailingTransaction(real, calls++);
|
||||
transactions.put(real.get_uid(), tx);
|
||||
return tx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransactionTimeout(int i) throws SystemException {
|
||||
tm.setTransactionTimeout(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction suspend() throws SystemException {
|
||||
Transaction real = tm.suspend();
|
||||
if (real == null) {
|
||||
return null;
|
||||
}
|
||||
return transactions.get(((com.arjuna.ats.jta.transaction.Transaction) real).get_uid());
|
||||
}
|
||||
|
||||
public int getFailures() {
|
||||
return failures.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume(Transaction transaction) throws InvalidTransactionException, IllegalStateException, SystemException {
|
||||
tm.resume(((FailingTransaction)transaction).transaction);
|
||||
}
|
||||
|
||||
private final class FailingTransaction implements Transaction {
|
||||
|
||||
private final com.arjuna.ats.jta.transaction.Transaction transaction;
|
||||
private final int number;
|
||||
|
||||
private FailingTransaction(com.arjuna.ats.jta.transaction.Transaction transaction, int number) {
|
||||
this.transaction = transaction;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException {
|
||||
if (number < limit) {
|
||||
transaction.commit();
|
||||
transactions.remove(transaction.get_uid());
|
||||
} else {
|
||||
int fails = failures.incrementAndGet();
|
||||
RollbackException ex = new RollbackException("Expected rollback for test");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean delistResource(XAResource arg0, int arg1) throws IllegalStateException, SystemException {
|
||||
return transaction.delistResource(arg0, arg1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enlistResource(XAResource arg0) throws RollbackException, IllegalStateException, SystemException {
|
||||
return transaction.enlistResource(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() throws SystemException {
|
||||
return transaction.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSynchronization(Synchronization arg0) throws RollbackException, IllegalStateException, SystemException {
|
||||
transaction.registerSynchronization(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() throws IllegalStateException, SystemException {
|
||||
transaction.rollback();
|
||||
transactions.remove(transaction.get_uid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||
transaction.setRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FailingTransaction{" + "transaction=" + transaction.get_uid() + ", number=" + number + '}';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.jms.bridge;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory;
|
||||
import org.apache.activemq.artemis.jms.bridge.DestinationFactory;
|
||||
import org.apache.activemq.artemis.jms.bridge.QualityOfServiceMode;
|
||||
import org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* A JMSBridgeClusteredTest
|
||||
* <br>
|
||||
* Tests of jms bridge using HA connection factories.
|
||||
*/
|
||||
public class JMSBridgeClusteredTest extends ClusteredBridgeTestBase {
|
||||
private static final Logger log = Logger.getLogger(JMSBridgeClusteredTest.class);
|
||||
|
||||
private ServerGroup sourceServer;
|
||||
private ServerGroup targetServer;
|
||||
|
||||
private String sourceQueueName = "SourceQueue";
|
||||
private String targetQueueName = "TargetQueue";
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
sourceServer = createServerGroup("source-server");
|
||||
targetServer = createServerGroup("target-server");
|
||||
|
||||
sourceServer.start();
|
||||
targetServer.start();
|
||||
|
||||
sourceServer.createQueue(sourceQueueName);
|
||||
targetServer.createQueue(targetQueueName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBridgeOnFailoverXA() throws Exception {
|
||||
performSourceAndTargetCrashAndFailover(QualityOfServiceMode.ONCE_AND_ONLY_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBridgeOnFailoverDupsOk() throws Exception {
|
||||
performSourceAndTargetCrashAndFailover(QualityOfServiceMode.DUPLICATES_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBridgeOnFailoverAtMostOnce() throws Exception {
|
||||
performSourceAndTargetCrashAndFailover(QualityOfServiceMode.AT_MOST_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrashAndFailoverWithMessagesXA() throws Exception {
|
||||
performSourceAndTargetCrashAndFailoverWithMessages(QualityOfServiceMode.ONCE_AND_ONLY_ONCE);
|
||||
}
|
||||
|
||||
//test messages are correctly bridged when failover happens during a batch send.
|
||||
//first send some messages, make sure bridge doesn't send it (below batch size)
|
||||
//then crash the live
|
||||
//then send more messages
|
||||
//then receive those messages, no more, no less.
|
||||
//this test are valid for ONCE_AND_ONLY_ONCE and AT_MOST_ONCE.
|
||||
//with DUPS_OK the test failed because some messages are delivered again
|
||||
//after failover, which is fine as in this mode duplication is allowed.
|
||||
public void performSourceAndTargetCrashAndFailoverWithMessages(QualityOfServiceMode mode) throws Exception {
|
||||
JMSBridgeImpl bridge = null;
|
||||
TransactionManager txMgr = null;
|
||||
|
||||
try {
|
||||
ConnectionFactoryFactory sourceCFF = sourceServer.getConnectionFactoryFactory();
|
||||
ConnectionFactoryFactory targetCFF = targetServer.getConnectionFactoryFactory();
|
||||
DestinationFactory sourceQueueFactory = sourceServer.getDestinationFactory(sourceQueueName);
|
||||
DestinationFactory targetQueueFactory = targetServer.getDestinationFactory(targetQueueName);
|
||||
|
||||
//even number
|
||||
final int batchSize = 4;
|
||||
bridge = new JMSBridgeImpl(sourceCFF, targetCFF, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, mode, batchSize, -1, null, null, false).setBridgeName("test-bridge");
|
||||
|
||||
txMgr = newTransactionManager();
|
||||
bridge.setTransactionManager(txMgr);
|
||||
|
||||
//start the bridge
|
||||
bridge.start();
|
||||
|
||||
log.debug("started bridge");
|
||||
|
||||
final int NUM_MESSAGES = batchSize / 2;
|
||||
|
||||
//send some messages to source
|
||||
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
|
||||
//receive from target, no message should be received.
|
||||
receiveMessages(targetServer, targetQueueName, 0);
|
||||
|
||||
//now crash target server
|
||||
targetServer.crashLive();
|
||||
|
||||
//send more
|
||||
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
|
||||
|
||||
receiveMessages(targetServer, targetQueueName, batchSize);
|
||||
|
||||
//send some again
|
||||
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
|
||||
//check no messages arrived.
|
||||
receiveMessages(targetServer, targetQueueName, 0);
|
||||
//now crash source server
|
||||
sourceServer.crashLive();
|
||||
|
||||
//verify bridge still work
|
||||
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
|
||||
receiveMessages(targetServer, targetQueueName, batchSize);
|
||||
} finally {
|
||||
if (bridge != null) {
|
||||
bridge.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deploy a bridge, source and target queues are in
|
||||
* separate live/backup pairs. Source and Target CF are ha.
|
||||
* Test the bridge work when the live servers crash.
|
||||
*/
|
||||
private void performSourceAndTargetCrashAndFailover(QualityOfServiceMode mode) throws Exception {
|
||||
|
||||
JMSBridgeImpl bridge = null;
|
||||
TransactionManager txMgr = null;
|
||||
|
||||
try {
|
||||
ConnectionFactoryFactory sourceCFF = sourceServer.getConnectionFactoryFactory();
|
||||
ConnectionFactoryFactory targetCFF = targetServer.getConnectionFactoryFactory();
|
||||
DestinationFactory sourceQueueFactory = sourceServer.getDestinationFactory(sourceQueueName);
|
||||
DestinationFactory targetQueueFactory = targetServer.getDestinationFactory(targetQueueName);
|
||||
|
||||
bridge = new JMSBridgeImpl(sourceCFF, targetCFF, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, mode, 10, 1000, null, null, false).setBridgeName("test-bridge");
|
||||
|
||||
txMgr = newTransactionManager();
|
||||
bridge.setTransactionManager(txMgr);
|
||||
|
||||
//start the bridge
|
||||
bridge.start();
|
||||
|
||||
final int NUM_MESSAGES = 10;
|
||||
|
||||
//send some messages to source
|
||||
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
|
||||
//receive from target
|
||||
receiveMessages(targetServer, targetQueueName, NUM_MESSAGES);
|
||||
|
||||
//now crash target server
|
||||
targetServer.crashLive();
|
||||
|
||||
//verify bridge still works
|
||||
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
|
||||
receiveMessages(targetServer, targetQueueName, NUM_MESSAGES);
|
||||
|
||||
//now crash source server
|
||||
sourceServer.crashLive();
|
||||
|
||||
//verify bridge still work
|
||||
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
|
||||
receiveMessages(targetServer, targetQueueName, NUM_MESSAGES, mode == QualityOfServiceMode.ONCE_AND_ONLY_ONCE);
|
||||
} finally {
|
||||
if (bridge != null) {
|
||||
bridge.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMessages(ServerGroup server, String queueName, int num) throws ActiveMQException {
|
||||
server.sendMessages(queueName, num);
|
||||
}
|
||||
|
||||
private void receiveMessages(ServerGroup server,
|
||||
String queueName,
|
||||
int num,
|
||||
boolean checkDup) throws ActiveMQException {
|
||||
try {
|
||||
server.receiveMessages(queueName, num, checkDup);
|
||||
} catch (ActiveMQException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void receiveMessages(ServerGroup server, String queueName, int num) throws ActiveMQException {
|
||||
try {
|
||||
server.receiveMessages(queueName, num, false);
|
||||
} catch (ActiveMQException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected TransactionManager newTransactionManager() {
|
||||
return new TransactionManagerImple();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,413 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.jms.bridge;
|
||||
|
||||
import javax.transaction.HeuristicMixedException;
|
||||
import javax.transaction.HeuristicRollbackException;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.Synchronization;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.xa.XAResource;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
|
||||
import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory;
|
||||
import org.apache.activemq.artemis.jms.bridge.QualityOfServiceMode;
|
||||
import org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory;
|
||||
import org.apache.activemq.artemis.tests.integration.ra.DummyTransactionManager;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JMSBridgeReconnectionTest extends BridgeTestBase {
|
||||
private static final Logger log = Logger.getLogger(JMSBridgeReconnectionTest.class);
|
||||
|
||||
private static final int TIME_WAIT = 5000;
|
||||
|
||||
// Crash and reconnect
|
||||
|
||||
// Once and only once
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestBasic_OnceAndOnlyOnce_P() throws Exception {
|
||||
performCrashAndReconnectDestBasic(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestBasic_OnceAndOnlyOnce_P_LargeMessage() throws Exception {
|
||||
performCrashAndReconnectDestBasic(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestBasic_OnceAndOnlyOnce_NP() throws Exception {
|
||||
performCrashAndReconnectDestBasic(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false, false);
|
||||
}
|
||||
|
||||
// dups ok
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestBasic_DuplicatesOk_P() throws Exception {
|
||||
performCrashAndReconnectDestBasic(QualityOfServiceMode.DUPLICATES_OK, true, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestBasic_DuplicatesOk_NP() throws Exception {
|
||||
performCrashAndReconnectDestBasic(QualityOfServiceMode.DUPLICATES_OK, false, false);
|
||||
}
|
||||
|
||||
// At most once
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestBasic_AtMostOnce_P() throws Exception {
|
||||
performCrashAndReconnectDestBasic(QualityOfServiceMode.AT_MOST_ONCE, true, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestBasic_AtMostOnce_NP() throws Exception {
|
||||
performCrashAndReconnectDestBasic(QualityOfServiceMode.AT_MOST_ONCE, false, false);
|
||||
}
|
||||
|
||||
// Crash tests specific to XA transactions
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestCrashBeforePrepare_P() throws Exception {
|
||||
performCrashAndReconnectDestCrashBeforePrepare(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrashAndReconnectDestCrashBeforePrepare_NP() throws Exception {
|
||||
performCrashAndReconnectDestCrashBeforePrepare(false);
|
||||
}
|
||||
|
||||
// Crash before bridge is started
|
||||
|
||||
@Test
|
||||
public void testRetryConnectionOnStartup() throws Exception {
|
||||
server1.stop();
|
||||
|
||||
JMSBridgeImpl bridge = new JMSBridgeImpl(cff0, cff1, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, QualityOfServiceMode.DUPLICATES_OK, 10, -1, null, null, false).setBridgeName("test-bridge");
|
||||
bridge.setTransactionManager(newTransactionManager());
|
||||
addActiveMQComponent(bridge);
|
||||
bridge.start();
|
||||
Assert.assertFalse(bridge.isStarted());
|
||||
Assert.assertTrue(bridge.isFailed());
|
||||
|
||||
// Restart the server
|
||||
server1.start();
|
||||
|
||||
createQueue("targetQueue", 1);
|
||||
setUpAdministeredObjects();
|
||||
|
||||
Thread.sleep(3000);
|
||||
|
||||
Assert.assertTrue(bridge.isStarted());
|
||||
Assert.assertFalse(bridge.isFailed());
|
||||
}
|
||||
|
||||
/**
|
||||
* https://jira.jboss.org/jira/browse/HORNETQ-287
|
||||
*/
|
||||
@Test
|
||||
public void testStopBridgeWithFailureWhenStarted() throws Exception {
|
||||
server1.stop();
|
||||
|
||||
JMSBridgeImpl bridge = new JMSBridgeImpl(cff0, cff1, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 500, -1, QualityOfServiceMode.DUPLICATES_OK, 10, -1, null, null, false).setBridgeName("test-bridge");
|
||||
bridge.setTransactionManager(newTransactionManager());
|
||||
|
||||
bridge.start();
|
||||
Assert.assertFalse(bridge.isStarted());
|
||||
Assert.assertTrue(bridge.isFailed());
|
||||
|
||||
bridge.stop();
|
||||
Assert.assertFalse(bridge.isStarted());
|
||||
|
||||
// we restart and setup the server for the test's tearDown checks
|
||||
server1.start();
|
||||
createQueue("targetQueue", 1);
|
||||
setUpAdministeredObjects();
|
||||
}
|
||||
|
||||
/*
|
||||
* Send some messages
|
||||
* Crash the destination server
|
||||
* Bring the destination server back up
|
||||
* Send some more messages
|
||||
* Verify all messages are received
|
||||
*/
|
||||
private void performCrashAndReconnectDestBasic(final QualityOfServiceMode qosMode,
|
||||
final boolean persistent,
|
||||
final boolean largeMessage) throws Exception {
|
||||
JMSBridgeImpl bridge = null;
|
||||
|
||||
ConnectionFactoryFactory factInUse0 = cff0;
|
||||
ConnectionFactoryFactory factInUse1 = cff1;
|
||||
if (qosMode.equals(QualityOfServiceMode.ONCE_AND_ONLY_ONCE)) {
|
||||
factInUse0 = cff0xa;
|
||||
factInUse1 = cff1xa;
|
||||
}
|
||||
|
||||
bridge = new JMSBridgeImpl(factInUse0, factInUse1, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, qosMode, 10, -1, null, null, false).setBridgeName("test-bridge");
|
||||
addActiveMQComponent(bridge);
|
||||
bridge.setTransactionManager(newTransactionManager());
|
||||
bridge.start();
|
||||
|
||||
final int NUM_MESSAGES = 10;
|
||||
|
||||
// Send some messages
|
||||
|
||||
sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES / 2, persistent, largeMessage);
|
||||
|
||||
// Verify none are received
|
||||
|
||||
checkEmpty(targetQueue, 1);
|
||||
|
||||
// Now crash the dest server
|
||||
|
||||
instanceLog.debug("About to crash server");
|
||||
|
||||
server1.stop();
|
||||
|
||||
// Wait a while before starting up to simulate the dest being down for a while
|
||||
instanceLog.debug("Waiting 5 secs before bringing server back up");
|
||||
Thread.sleep(TIME_WAIT);
|
||||
instanceLog.debug("Done wait");
|
||||
|
||||
// Restart the server
|
||||
instanceLog.debug("Restarting server");
|
||||
server1.start();
|
||||
|
||||
// jmsServer1.createQueue(false, "targetQueue", null, true, "queue/targetQueue");
|
||||
|
||||
createQueue("targetQueue", 1);
|
||||
|
||||
setUpAdministeredObjects();
|
||||
|
||||
// Send some more messages
|
||||
|
||||
instanceLog.debug("Sending more messages");
|
||||
|
||||
sendMessages(cf0, sourceQueue, NUM_MESSAGES / 2, NUM_MESSAGES / 2, persistent, largeMessage);
|
||||
|
||||
instanceLog.debug("Sent messages");
|
||||
|
||||
server1.stop();
|
||||
|
||||
bridge.stop();
|
||||
|
||||
log.debug("JMSBridgeReconnectionTest.performCrashAndReconnectDestBasic");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performCrashDestinationStopBridge() throws Exception {
|
||||
ConnectionFactoryFactory factInUse0 = cff0;
|
||||
ConnectionFactoryFactory factInUse1 = cff1;
|
||||
final JMSBridgeImpl bridge = new JMSBridgeImpl(factInUse0, factInUse1, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, QualityOfServiceMode.DUPLICATES_OK, 10, -1, null, null, false).setBridgeName("test-bridge");
|
||||
|
||||
addActiveMQComponent(bridge);
|
||||
bridge.setTransactionManager(newTransactionManager());
|
||||
bridge.start();
|
||||
|
||||
Thread clientThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (bridge.isStarted()) {
|
||||
try {
|
||||
sendMessages(cf0, sourceQueue, 0, 1, false, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
clientThread.start();
|
||||
|
||||
checkAllMessageReceivedInOrder(cf1, targetQueue, 0, 1, false);
|
||||
|
||||
instanceLog.debug("About to crash server");
|
||||
|
||||
server1.stop();
|
||||
|
||||
// Wait a while before starting up to simulate the dest being down for a while
|
||||
instanceLog.debug("Waiting 5 secs before bringing server back up");
|
||||
Thread.sleep(TIME_WAIT);
|
||||
instanceLog.debug("Done wait");
|
||||
|
||||
bridge.stop();
|
||||
|
||||
clientThread.join(5000);
|
||||
|
||||
assertTrue(!clientThread.isAlive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performCrashAndReconnect() throws Exception {
|
||||
performCrashAndReconnect(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void performCrashAndNoReconnect() throws Exception {
|
||||
performCrashAndReconnect(false);
|
||||
}
|
||||
|
||||
private void performCrashAndReconnect(boolean restart) throws Exception {
|
||||
cff1xa = new ConnectionFactoryFactory() {
|
||||
@Override
|
||||
public Object createConnectionFactory() throws Exception {
|
||||
ActiveMQXAConnectionFactory cf = (ActiveMQXAConnectionFactory) ActiveMQJMSClient.createConnectionFactoryWithHA(JMSFactoryType.XA_CF, new TransportConfiguration(INVM_CONNECTOR_FACTORY, params1));
|
||||
|
||||
// Note! We disable automatic reconnection on the session factory. The bridge needs to do the reconnection
|
||||
cf.setReconnectAttempts(-1);
|
||||
cf.setBlockOnNonDurableSend(true);
|
||||
cf.setBlockOnDurableSend(true);
|
||||
cf.setCacheLargeMessagesClient(true);
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DummyTransactionManager tm = new DummyTransactionManager();
|
||||
DummyTransaction tx = new DummyTransaction();
|
||||
tm.tx = tx;
|
||||
|
||||
JMSBridgeImpl bridge = new JMSBridgeImpl(cff0xa, cff1xa, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, QualityOfServiceMode.ONCE_AND_ONLY_ONCE, 10, 5000, null, null, false).setBridgeName("test-bridge");
|
||||
addActiveMQComponent(bridge);
|
||||
bridge.setTransactionManager(tm);
|
||||
|
||||
bridge.start();
|
||||
|
||||
// Now crash the dest server
|
||||
|
||||
instanceLog.debug("About to crash server");
|
||||
|
||||
server1.stop();
|
||||
|
||||
if (restart) {
|
||||
server1.start();
|
||||
}
|
||||
// Wait a while before starting up to simulate the dest being down for a while
|
||||
instanceLog.debug("Waiting 5 secs before bringing server back up");
|
||||
Thread.sleep(TIME_WAIT);
|
||||
instanceLog.debug("Done wait");
|
||||
|
||||
bridge.stop();
|
||||
|
||||
if (restart) {
|
||||
assertTrue(tx.rolledback);
|
||||
assertTrue(tx.targetConnected);
|
||||
} else {
|
||||
assertTrue(tx.rolledback);
|
||||
assertFalse(tx.targetConnected);
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyTransaction implements Transaction {
|
||||
|
||||
boolean rolledback = false;
|
||||
ClientSession targetSession;
|
||||
boolean targetConnected = false;
|
||||
|
||||
@Override
|
||||
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, SystemException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() throws IllegalStateException, SystemException {
|
||||
rolledback = true;
|
||||
targetConnected = !targetSession.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() throws SystemException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enlistResource(XAResource xaResource) throws RollbackException, IllegalStateException, SystemException {
|
||||
targetSession = (ClientSession) xaResource;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException, SystemException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSynchronization(Synchronization synchronization) throws RollbackException, IllegalStateException, SystemException {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send some messages
|
||||
* Crash the destination server
|
||||
* Set the max batch time such that it will attempt to send the batch while the dest server is down
|
||||
* Bring up the destination server
|
||||
* Send some more messages
|
||||
* Verify all messages are received
|
||||
*/
|
||||
private void performCrashAndReconnectDestCrashBeforePrepare(final boolean persistent) throws Exception {
|
||||
JMSBridgeImpl bridge = new JMSBridgeImpl(cff0xa, cff1xa, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, QualityOfServiceMode.ONCE_AND_ONLY_ONCE, 10, 5000, null, null, false).setBridgeName("test-bridge");
|
||||
addActiveMQComponent(bridge);
|
||||
bridge.setTransactionManager(newTransactionManager());
|
||||
|
||||
bridge.start();
|
||||
|
||||
final int NUM_MESSAGES = 10;
|
||||
// Send some messages
|
||||
|
||||
sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES / 2, persistent, false);
|
||||
|
||||
// verify none are received
|
||||
|
||||
checkEmpty(targetQueue, 1);
|
||||
|
||||
// Now crash the dest server
|
||||
|
||||
instanceLog.debug("About to crash server");
|
||||
|
||||
server1.stop();
|
||||
|
||||
// Wait a while before starting up to simulate the dest being down for a while
|
||||
instanceLog.debug("Waiting 5 secs before bringing server back up");
|
||||
Thread.sleep(TIME_WAIT);
|
||||
instanceLog.debug("Done wait");
|
||||
|
||||
// Restart the server
|
||||
server1.start();
|
||||
|
||||
createQueue("targetQueue", 1);
|
||||
|
||||
setUpAdministeredObjects();
|
||||
|
||||
sendMessages(cf0, sourceQueue, NUM_MESSAGES / 2, NUM_MESSAGES / 2, persistent, false);
|
||||
|
||||
checkMessagesReceived(cf1, targetQueue, QualityOfServiceMode.ONCE_AND_ONLY_ONCE, NUM_MESSAGES, false, false);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.jms.bridge;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.apache.activemq.artemis.service.extensions.transactions.TransactionManagerLocator;
|
||||
|
||||
public class TransactionManagerLocatorImpl implements TransactionManagerLocator {
|
||||
|
||||
private static TransactionManager tm = null;
|
||||
|
||||
@Override
|
||||
public TransactionManager getTransactionManager() {
|
||||
return tm;
|
||||
}
|
||||
|
||||
public static void setTransactionManager(TransactionManager transactionManager) {
|
||||
tm = transactionManager;
|
||||
}
|
||||
}
|
|
@ -1,544 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.jms.ra;
|
||||
|
||||
import javax.jms.Message;
|
||||
import javax.resource.ResourceException;
|
||||
import javax.resource.spi.LocalTransactionException;
|
||||
import javax.resource.spi.UnavailableException;
|
||||
import javax.resource.spi.endpoint.MessageEndpoint;
|
||||
import javax.resource.spi.endpoint.MessageEndpointFactory;
|
||||
import javax.transaction.HeuristicMixedException;
|
||||
import javax.transaction.HeuristicRollbackException;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.arjuna.ats.arjuna.coordinator.TransactionReaper;
|
||||
import com.arjuna.ats.arjuna.coordinator.TxControl;
|
||||
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.server.ServerConsumer;
|
||||
import org.apache.activemq.artemis.core.server.ServerSession;
|
||||
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
|
||||
import org.apache.activemq.artemis.ra.ActiveMQResourceAdapter;
|
||||
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivation;
|
||||
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivationSpec;
|
||||
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||
import org.apache.activemq.artemis.tests.integration.ra.ActiveMQRATestBase;
|
||||
import org.apache.activemq.artemis.utils.RandomUtil;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Simulates several messages being received over multiple instances with reconnects during the process.
|
||||
*/
|
||||
public class MDBMultipleHandlersServerDisconnectTest extends ActiveMQRATestBase {
|
||||
private static final Logger log = Logger.getLogger(MDBMultipleHandlersServerDisconnectTest.class);
|
||||
|
||||
final ConcurrentHashMap<Integer, AtomicInteger> mapCounter = new ConcurrentHashMap<>();
|
||||
|
||||
volatile ActiveMQResourceAdapter resourceAdapter;
|
||||
|
||||
ServerLocator nettyLocator;
|
||||
|
||||
// This thread will keep bugging the handlers.
|
||||
// if they behave well with XA, the test pass!
|
||||
final AtomicBoolean running = new AtomicBoolean(true);
|
||||
|
||||
private volatile boolean playTXTimeouts = true;
|
||||
private volatile boolean playServerClosingSession = true;
|
||||
private volatile boolean playServerClosingConsumer = true;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
nettyLocator = createNettyNonHALocator();
|
||||
nettyLocator.setRetryInterval(100);
|
||||
nettyLocator.setReconnectAttempts(300);
|
||||
mapCounter.clear();
|
||||
resourceAdapter = null;
|
||||
super.setUp();
|
||||
createQueue(true, "outQueue");
|
||||
DummyTMLocator.startTM();
|
||||
running.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
DummyTMLocator.stopTM();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean usePersistence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSecurity() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReconnectMDBNoMessageLoss() throws Exception {
|
||||
AddressSettings settings = new AddressSettings();
|
||||
settings.setRedeliveryDelay(100);
|
||||
settings.setMaxDeliveryAttempts(-1);
|
||||
server.getAddressSettingsRepository().clear();
|
||||
server.getAddressSettingsRepository().addMatch("#", settings);
|
||||
ActiveMQResourceAdapter qResourceAdapter = newResourceAdapter();
|
||||
resourceAdapter = qResourceAdapter;
|
||||
resourceAdapter.setConfirmationWindowSize(-1);
|
||||
resourceAdapter.setCallTimeout(1000L);
|
||||
resourceAdapter.setConsumerWindowSize(1024 * 1024);
|
||||
resourceAdapter.setReconnectAttempts(-1);
|
||||
resourceAdapter.setRetryInterval(100L);
|
||||
|
||||
// qResourceAdapter.setTransactionManagerLocatorClass(DummyTMLocator.class.getName());
|
||||
// qResourceAdapter.setTransactionManagerLocatorMethod("getTM");
|
||||
|
||||
MyBootstrapContext ctx = new MyBootstrapContext();
|
||||
|
||||
qResourceAdapter.setConnectorClassName(NETTY_CONNECTOR_FACTORY);
|
||||
qResourceAdapter.start(ctx);
|
||||
|
||||
final int NUMBER_OF_SESSIONS = 10;
|
||||
|
||||
ActiveMQActivationSpec spec = new ActiveMQActivationSpec();
|
||||
|
||||
spec.setTransactionTimeout(1);
|
||||
spec.setMaxSession(NUMBER_OF_SESSIONS);
|
||||
spec.setSetupAttempts(-1);
|
||||
spec.setSetupInterval(100L);
|
||||
spec.setResourceAdapter(qResourceAdapter);
|
||||
spec.setUseJNDI(false);
|
||||
spec.setDestinationType("javax.jms.Queue");
|
||||
spec.setDestination(MDBQUEUE);
|
||||
|
||||
// Some the routines would be screwed up if using the default one
|
||||
Assert.assertFalse(spec.isHasBeenUpdated());
|
||||
|
||||
TestEndpointFactory endpointFactory = new TestEndpointFactory(true);
|
||||
qResourceAdapter.endpointActivation(endpointFactory, spec);
|
||||
|
||||
Assert.assertEquals(1, resourceAdapter.getActivations().values().size());
|
||||
ActiveMQActivation activation = resourceAdapter.getActivations().values().toArray(new ActiveMQActivation[1])[0];
|
||||
|
||||
final int NUMBER_OF_MESSAGES = 1000;
|
||||
|
||||
Thread producer = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ServerLocator locator = createInVMLocator(0);
|
||||
ClientSessionFactory factory = locator.createSessionFactory();
|
||||
ClientSession session = factory.createSession(false, false);
|
||||
|
||||
ClientProducer clientProducer = session.createProducer(MDBQUEUEPREFIXED);
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
for (int b = 0; b < 500; b++) {
|
||||
buffer.append("ab");
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
|
||||
|
||||
ClientMessage message = session.createMessage(true);
|
||||
|
||||
message.getBodyBuffer().writeString(buffer.toString() + i);
|
||||
|
||||
message.putIntProperty("i", i);
|
||||
|
||||
clientProducer.send(message);
|
||||
|
||||
if (i % 100 == 0) {
|
||||
session.commit();
|
||||
}
|
||||
}
|
||||
session.commit();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
producer.start();
|
||||
|
||||
final AtomicBoolean metaDataFailed = new AtomicBoolean(false);
|
||||
|
||||
Thread buggerThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (running.get()) {
|
||||
try {
|
||||
Thread.sleep(RandomUtil.randomInterval(100, 200));
|
||||
} catch (InterruptedException intex) {
|
||||
intex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
List<ServerSession> serverSessions = lookupServerSessions("resource-adapter", NUMBER_OF_SESSIONS);
|
||||
|
||||
System.err.println("Contains " + serverSessions.size() + " RA sessions");
|
||||
|
||||
if (serverSessions.size() != NUMBER_OF_SESSIONS) {
|
||||
System.err.println("the server was supposed to have " + NUMBER_OF_MESSAGES + " RA Sessions but it only contained accordingly to the meta-data");
|
||||
metaDataFailed.set(true);
|
||||
} else if (serverSessions.size() == NUMBER_OF_SESSIONS) {
|
||||
// it became the same after some reconnect? which would be acceptable
|
||||
metaDataFailed.set(false);
|
||||
}
|
||||
|
||||
if (playServerClosingSession && serverSessions.size() > 0) {
|
||||
|
||||
int randomBother = RandomUtil.randomInterval(0, serverSessions.size() - 1);
|
||||
log.debug("bugging session " + randomBother);
|
||||
|
||||
ServerSession serverSession = serverSessions.get(randomBother);
|
||||
|
||||
if (playServerClosingConsumer && RandomUtil.randomBoolean()) {
|
||||
// will play this randomly, only half of the times
|
||||
for (ServerConsumer consumer : serverSession.getServerConsumers()) {
|
||||
try {
|
||||
// Simulating a rare race that could happen in production
|
||||
// where the consumer is closed while things are still happening
|
||||
consumer.close(true);
|
||||
Thread.sleep(100);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemotingConnection connection = serverSession.getRemotingConnection();
|
||||
|
||||
connection.fail(new ActiveMQException("failed at random " + randomBother));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
buggerThread.start();
|
||||
|
||||
ServerLocator locator = createInVMLocator(0);
|
||||
ClientSessionFactory factory = locator.createSessionFactory();
|
||||
ClientSession session = factory.createSession(false, false);
|
||||
session.start();
|
||||
|
||||
ClientConsumer consumer = session.createConsumer("outQueue");
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
|
||||
ClientMessage message = consumer.receive(60000);
|
||||
if (message == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == NUMBER_OF_MESSAGES * 0.50) {
|
||||
// This is to make sure the MDBs will survive a reboot
|
||||
// and no duplications or message loss will happen because of this
|
||||
System.err.println("Rebooting the MDBs at least once!");
|
||||
activation.startReconnectThread("I");
|
||||
}
|
||||
|
||||
if (i == NUMBER_OF_MESSAGES * 0.90) {
|
||||
log.debug("Disabled failures at " + i);
|
||||
playTXTimeouts = false;
|
||||
playServerClosingSession = false;
|
||||
playServerClosingConsumer = false;
|
||||
|
||||
}
|
||||
|
||||
log.debug("Received " + i + " messages");
|
||||
|
||||
doReceiveMessage(message);
|
||||
|
||||
if (i % 200 == 0) {
|
||||
log.debug("received " + i);
|
||||
session.commit();
|
||||
}
|
||||
}
|
||||
|
||||
session.commit();
|
||||
|
||||
while (true) {
|
||||
ClientMessage message = consumer.receiveImmediate();
|
||||
if (message == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
log.debug("Received extra message " + message);
|
||||
|
||||
doReceiveMessage(message);
|
||||
}
|
||||
|
||||
session.commit();
|
||||
|
||||
Assert.assertNull(consumer.receiveImmediate());
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
PrintWriter out = new PrintWriter(writer);
|
||||
|
||||
boolean failed = false;
|
||||
for (int i = 0; i < NUMBER_OF_MESSAGES; i++) {
|
||||
AtomicInteger atomicInteger = mapCounter.get(Integer.valueOf(i));
|
||||
|
||||
if (atomicInteger == null) {
|
||||
out.println("didn't receive message with i=" + i);
|
||||
failed = true;
|
||||
} else if (atomicInteger.get() > 1) {
|
||||
out.println("message with i=" + i + " received " + atomicInteger.get() + " times");
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
running.set(false);
|
||||
|
||||
buggerThread.join();
|
||||
producer.join();
|
||||
|
||||
qResourceAdapter.stop();
|
||||
|
||||
session.close();
|
||||
|
||||
if (failed) {
|
||||
log.debug(writer.toString());
|
||||
}
|
||||
|
||||
Assert.assertFalse(writer.toString(), failed);
|
||||
|
||||
log.debug("Received " + NUMBER_OF_MESSAGES + " messages");
|
||||
|
||||
Assert.assertFalse("There was meta-data failures, some sessions didn't reconnect properly", metaDataFailed.get());
|
||||
|
||||
}
|
||||
|
||||
private void doReceiveMessage(ClientMessage message) throws Exception {
|
||||
Assert.assertNotNull(message);
|
||||
message.acknowledge();
|
||||
Integer value = message.getIntProperty("i");
|
||||
AtomicInteger mapCount = new AtomicInteger(1);
|
||||
|
||||
mapCount = mapCounter.putIfAbsent(value, mapCount);
|
||||
|
||||
if (mapCount != null) {
|
||||
mapCount.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
private List<ServerSession> lookupServerSessions(String parameter, int numberOfSessions) {
|
||||
long timeout = System.currentTimeMillis() + 50000;
|
||||
List<ServerSession> serverSessions = new LinkedList<>();
|
||||
do {
|
||||
if (!serverSessions.isEmpty()) {
|
||||
System.err.println("Retry on serverSessions!!! currently with " + serverSessions.size());
|
||||
serverSessions.clear();
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (Exception e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
serverSessions.clear();
|
||||
for (ServerSession session : server.getSessions()) {
|
||||
if (session.getMetaData(parameter) != null) {
|
||||
serverSessions.add(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (running.get() && serverSessions.size() != numberOfSessions && timeout > System.currentTimeMillis());
|
||||
|
||||
System.err.println("Returning " + serverSessions.size() + " sessions");
|
||||
return serverSessions;
|
||||
}
|
||||
|
||||
protected class TestEndpointFactory implements MessageEndpointFactory {
|
||||
|
||||
private final boolean isDeliveryTransacted;
|
||||
|
||||
public TestEndpointFactory(boolean deliveryTransacted) {
|
||||
isDeliveryTransacted = deliveryTransacted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageEndpoint createEndpoint(XAResource xaResource) throws UnavailableException {
|
||||
TestEndpoint retEnd = new TestEndpoint();
|
||||
if (xaResource != null) {
|
||||
retEnd.setXAResource(xaResource);
|
||||
}
|
||||
return retEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageEndpoint createEndpoint(XAResource xaResource, long l) throws UnavailableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeliveryTransacted(Method method) throws NoSuchMethodException {
|
||||
return isDeliveryTransacted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivationName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getEndpointClass() {
|
||||
return TestEndpoint.class;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestEndpoint extends DummyMessageEndpoint {
|
||||
|
||||
ClientSessionFactory factory;
|
||||
ClientSession endpointSession;
|
||||
ClientProducer producer;
|
||||
|
||||
Transaction currentTX;
|
||||
|
||||
public TestEndpoint() {
|
||||
super(null);
|
||||
try {
|
||||
factory = nettyLocator.createSessionFactory();
|
||||
// buggingList.add(factory);
|
||||
endpointSession = factory.createSession(true, false, false);
|
||||
producer = endpointSession.createProducer("outQueue");
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDelivery(Method method) throws NoSuchMethodException, ResourceException {
|
||||
super.beforeDelivery(method);
|
||||
try {
|
||||
DummyTMLocator.tm.begin();
|
||||
currentTX = DummyTMLocator.tm.getTransaction();
|
||||
currentTX.enlistResource(xaResource);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message) {
|
||||
Integer value = 0;
|
||||
|
||||
try {
|
||||
value = message.getIntProperty("i");
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
|
||||
super.onMessage(message);
|
||||
|
||||
try {
|
||||
currentTX.enlistResource(endpointSession);
|
||||
ClientMessage message1 = endpointSession.createMessage(true);
|
||||
message1.putIntProperty("i", value);
|
||||
producer.send(message1);
|
||||
currentTX.delistResource(endpointSession, XAResource.TMSUCCESS);
|
||||
|
||||
if (playTXTimeouts) {
|
||||
if (RandomUtil.randomInterval(0, 5) == 3) {
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
currentTX.setRollbackOnly();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
e.printStackTrace();
|
||||
// throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDelivery() throws ResourceException {
|
||||
// This is a copy & paste of what the Application server would do here
|
||||
try {
|
||||
if (currentTX.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
|
||||
DummyTMLocator.tm.rollback();
|
||||
} else {
|
||||
DummyTMLocator.tm.commit();
|
||||
}
|
||||
} catch (HeuristicMixedException e) {
|
||||
throw new LocalTransactionException(e);
|
||||
} catch (SystemException e) {
|
||||
throw new LocalTransactionException(e);
|
||||
} catch (HeuristicRollbackException e) {
|
||||
throw new LocalTransactionException(e);
|
||||
} catch (RollbackException e) {
|
||||
throw new LocalTransactionException(e);
|
||||
}
|
||||
super.afterDelivery();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DummyTMLocator {
|
||||
|
||||
public static TransactionManagerImple tm;
|
||||
|
||||
public static void stopTM() {
|
||||
try {
|
||||
TransactionReaper.terminate(true);
|
||||
TxControl.disable(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
tm = null;
|
||||
}
|
||||
|
||||
public static void startTM() {
|
||||
tm = new TransactionManagerImple();
|
||||
TxControl.enable();
|
||||
}
|
||||
|
||||
public TransactionManager getTM() {
|
||||
return tm;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,734 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.activemq.artemis.tests.extras.jms.xa;
|
||||
|
||||
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.TextMessage;
|
||||
import javax.jms.Topic;
|
||||
import javax.jms.XAConnection;
|
||||
import javax.jms.XAConnectionFactory;
|
||||
import javax.jms.XASession;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
import javax.transaction.xa.XAException;
|
||||
import javax.transaction.xa.XAResource;
|
||||
import javax.transaction.xa.Xid;
|
||||
|
||||
import com.arjuna.ats.arjuna.coordinator.TransactionReaper;
|
||||
import com.arjuna.ats.arjuna.coordinator.TxControl;
|
||||
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
|
||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||
import org.apache.activemq.artemis.tests.util.JMSTestBase;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* A JMSXDeliveryCountTest
|
||||
*/
|
||||
public class JMSXDeliveryCountTest extends JMSTestBase {
|
||||
|
||||
Queue queue1;
|
||||
Topic topic1;
|
||||
|
||||
protected XAConnectionFactory xacf;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
xacf = ActiveMQJMSClient.createConnectionFactory("tcp://localhost:61616", "test");
|
||||
|
||||
queue1 = createQueue("queue1");
|
||||
topic1 = createTopic("topic1");
|
||||
|
||||
TxControl.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
TxControl.disable(true);
|
||||
|
||||
TransactionReaper.terminate(false);
|
||||
|
||||
super.tearDown();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleJMSXDeliveryCount() throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageProducer p = s.createProducer(queue1);
|
||||
p.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
|
||||
|
||||
p.send(s.createTextMessage("xoxo"));
|
||||
|
||||
s.close();
|
||||
|
||||
s = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
MessageConsumer c = s.createConsumer(queue1);
|
||||
|
||||
conn.start();
|
||||
|
||||
TextMessage tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("xoxo", tm.getText());
|
||||
Assert.assertTrue("JMSXDeliveryCount is supposed to exist as a property", tm.propertyExists("JMSXDeliveryCount"));
|
||||
Assert.assertEquals(1, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
s.recover();
|
||||
|
||||
tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("xoxo", tm.getText());
|
||||
Assert.assertTrue("JMSXDeliveryCount is supposed to exist as a property", tm.propertyExists("JMSXDeliveryCount"));
|
||||
Assert.assertEquals(2, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
tm.acknowledge();
|
||||
|
||||
conn.close();
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJMSXDeliveryCountNotDeliveredMessagesNotUpdated() throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
Session s = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
|
||||
MessageProducer p = s.createProducer(queue1);
|
||||
|
||||
p.send(s.createTextMessage("message1"));
|
||||
p.send(s.createTextMessage("message2"));
|
||||
p.send(s.createTextMessage("message3"));
|
||||
p.send(s.createTextMessage("message4"));
|
||||
p.send(s.createTextMessage("message5"));
|
||||
|
||||
MessageConsumer c = s.createConsumer(queue1);
|
||||
|
||||
conn.start();
|
||||
|
||||
TextMessage tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("message1", tm.getText());
|
||||
Assert.assertFalse(tm.getJMSRedelivered());
|
||||
Assert.assertEquals(1, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
s.close();
|
||||
|
||||
s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
c = s.createConsumer(queue1);
|
||||
|
||||
tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("message1", tm.getText());
|
||||
Assert.assertTrue(tm.getJMSRedelivered());
|
||||
Assert.assertEquals(2, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("message2", tm.getText());
|
||||
Assert.assertFalse(tm.getJMSRedelivered());
|
||||
Assert.assertEquals(1, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("message3", tm.getText());
|
||||
Assert.assertFalse(tm.getJMSRedelivered());
|
||||
Assert.assertEquals(1, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("message4", tm.getText());
|
||||
Assert.assertFalse(tm.getJMSRedelivered());
|
||||
Assert.assertEquals(1, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
tm = (TextMessage) c.receive(1000);
|
||||
|
||||
Assert.assertEquals("message5", tm.getText());
|
||||
Assert.assertFalse(tm.getJMSRedelivered());
|
||||
Assert.assertEquals(1, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
tm.acknowledge();
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedeliveryOnQueue() throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
Session sess1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
|
||||
MessageProducer prod = sess1.createProducer(queue1);
|
||||
|
||||
prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
|
||||
|
||||
final int NUM_MESSAGES = 100;
|
||||
|
||||
final int NUM_RECOVERIES = 8;
|
||||
|
||||
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||
TextMessage tm = sess1.createTextMessage();
|
||||
tm.setText("testing" + i);
|
||||
prod.send(tm);
|
||||
}
|
||||
|
||||
Session sess2 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
|
||||
MessageConsumer cons = sess2.createConsumer(queue1);
|
||||
|
||||
conn.start();
|
||||
|
||||
TextMessage tm = null;
|
||||
|
||||
for (int j = 0; j < NUM_RECOVERIES; j++) {
|
||||
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||
tm = (TextMessage) cons.receive(3000);
|
||||
Assert.assertNotNull(tm);
|
||||
Assert.assertEquals("testing" + i, tm.getText());
|
||||
Assert.assertTrue("JMSXDeliveryCount is supposed to exist as a property", tm.propertyExists("JMSXDeliveryCount"));
|
||||
Assert.assertEquals(j + 1, tm.getIntProperty("JMSXDeliveryCount"));
|
||||
}
|
||||
if (j != NUM_RECOVERIES - 1) {
|
||||
sess2.recover();
|
||||
}
|
||||
}
|
||||
|
||||
tm.acknowledge();
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedeliveryOnTopic() throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
conn.setClientID("myclientid");
|
||||
|
||||
Session sess1 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
Session sess2 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
Session sess3 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
|
||||
MessageConsumer cons1 = sess1.createConsumer(topic1);
|
||||
MessageConsumer cons2 = sess2.createConsumer(topic1);
|
||||
MessageConsumer cons3 = sess3.createDurableSubscriber(topic1, "subxyz");
|
||||
|
||||
conn.start();
|
||||
|
||||
final int NUM_MESSAGES = 100;
|
||||
final int NUM_RECOVERIES = 9;
|
||||
|
||||
Receiver r1 = new Receiver("R1", sess1, cons1, NUM_MESSAGES, NUM_RECOVERIES);
|
||||
Receiver r2 = new Receiver("R2", sess2, cons2, NUM_MESSAGES, NUM_RECOVERIES);
|
||||
Receiver r3 = new Receiver("R3", sess3, cons3, NUM_MESSAGES, NUM_RECOVERIES);
|
||||
|
||||
Thread t1 = new Thread(r1);
|
||||
Thread t2 = new Thread(r2);
|
||||
Thread t3 = new Thread(r3);
|
||||
|
||||
t1.start();
|
||||
t2.start();
|
||||
t3.start();
|
||||
|
||||
Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageProducer prod = sessSend.createProducer(topic1);
|
||||
prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
|
||||
|
||||
for (int i = 0; i < NUM_MESSAGES; i++) {
|
||||
TextMessage tm1 = sessSend.createTextMessage("testing" + i);
|
||||
prod.send(tm1);
|
||||
}
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
|
||||
Assert.assertFalse(r1.failed);
|
||||
Assert.assertFalse(r2.failed);
|
||||
Assert.assertFalse(r3.failed);
|
||||
|
||||
cons3.close();
|
||||
|
||||
sess3.unsubscribe("subxyz");
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeliveryCountUpdatedOnCloseTransacted() throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
Session producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageProducer producer = producerSess.createProducer(queue1);
|
||||
|
||||
Session consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
|
||||
MessageConsumer consumer = consumerSess.createConsumer(queue1);
|
||||
conn.start();
|
||||
|
||||
TextMessage tm = producerSess.createTextMessage("message1");
|
||||
|
||||
producer.send(tm);
|
||||
|
||||
TextMessage rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertTrue("JMSXDeliveryCount is supposed to exist as a property", tm.propertyExists("JMSXDeliveryCount"));
|
||||
Assert.assertEquals(1, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertFalse(rm.getJMSRedelivered());
|
||||
|
||||
consumerSess.rollback();
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(2, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
consumerSess.rollback();
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(3, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
// Now close the session without committing
|
||||
|
||||
consumerSess.close();
|
||||
|
||||
consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
|
||||
|
||||
consumer = consumerSess.createConsumer(queue1);
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(4, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
consumerSess.commit();
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeliveryCountUpdatedOnCloseClientAck() throws Exception {
|
||||
Connection conn = null;
|
||||
|
||||
try {
|
||||
conn = cf.createConnection();
|
||||
|
||||
Session producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageProducer producer = producerSess.createProducer(queue1);
|
||||
|
||||
Session consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
MessageConsumer consumer = consumerSess.createConsumer(queue1);
|
||||
conn.start();
|
||||
|
||||
TextMessage tm = producerSess.createTextMessage("message1");
|
||||
|
||||
producer.send(tm);
|
||||
|
||||
TextMessage rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(1, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertFalse(rm.getJMSRedelivered());
|
||||
|
||||
consumerSess.recover();
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(2, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
consumerSess.recover();
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(3, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
// Now close the session without committing
|
||||
|
||||
consumerSess.close();
|
||||
|
||||
consumerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
|
||||
|
||||
consumer = consumerSess.createConsumer(queue1);
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(4, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
rm.acknowledge();
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeliveryCountUpdatedOnCloseXA() throws Exception {
|
||||
XAConnection xaConn = null;
|
||||
|
||||
Connection conn = null;
|
||||
TransactionManager mgr = new TransactionManagerImple();
|
||||
|
||||
Transaction toResume = null;
|
||||
|
||||
Transaction tx = null;
|
||||
|
||||
try {
|
||||
toResume = mgr.suspend();
|
||||
|
||||
conn = cf.createConnection();
|
||||
|
||||
// Send a message
|
||||
|
||||
Session producerSess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageProducer producer = producerSess.createProducer(queue1);
|
||||
|
||||
TextMessage tm = producerSess.createTextMessage("message1");
|
||||
|
||||
producer.send(tm);
|
||||
|
||||
xaConn = xacf.createXAConnection();
|
||||
|
||||
XASession consumerSess = xaConn.createXASession();
|
||||
MessageConsumer consumer = consumerSess.createConsumer(queue1);
|
||||
xaConn.start();
|
||||
|
||||
DummyXAResource res = new DummyXAResource();
|
||||
|
||||
mgr.begin();
|
||||
|
||||
tx = mgr.getTransaction();
|
||||
|
||||
tx.enlistResource(res);
|
||||
|
||||
tx.enlistResource(consumerSess.getXAResource());
|
||||
|
||||
TextMessage rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(1, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertFalse(rm.getJMSRedelivered());
|
||||
|
||||
tx.delistResource(res, XAResource.TMSUCCESS);
|
||||
|
||||
tx.delistResource(consumerSess.getXAResource(), XAResource.TMSUCCESS);
|
||||
|
||||
mgr.rollback();
|
||||
|
||||
mgr.begin();
|
||||
|
||||
tx = mgr.getTransaction();
|
||||
|
||||
tx.enlistResource(res);
|
||||
|
||||
tx.enlistResource(consumerSess.getXAResource());
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(2, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
tx.delistResource(res, XAResource.TMSUCCESS);
|
||||
|
||||
tx.delistResource(consumerSess.getXAResource(), XAResource.TMSUCCESS);
|
||||
|
||||
mgr.rollback();
|
||||
|
||||
mgr.begin();
|
||||
|
||||
tx = mgr.getTransaction();
|
||||
|
||||
tx.enlistResource(res);
|
||||
|
||||
tx.enlistResource(consumerSess.getXAResource());
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(3, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
tx.delistResource(res, XAResource.TMSUCCESS);
|
||||
|
||||
tx.delistResource(consumerSess.getXAResource(), XAResource.TMSUCCESS);
|
||||
|
||||
mgr.rollback();
|
||||
|
||||
// Must close consumer first
|
||||
|
||||
consumer.close();
|
||||
|
||||
consumerSess.close();
|
||||
|
||||
consumerSess = xaConn.createXASession();
|
||||
|
||||
consumer = consumerSess.createConsumer(queue1);
|
||||
|
||||
mgr.begin();
|
||||
|
||||
tx = mgr.getTransaction();
|
||||
|
||||
tx.enlistResource(res);
|
||||
|
||||
tx.enlistResource(consumerSess.getXAResource());
|
||||
|
||||
rm = (TextMessage) consumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(rm);
|
||||
|
||||
Assert.assertEquals(tm.getText(), rm.getText());
|
||||
|
||||
Assert.assertEquals(4, rm.getIntProperty("JMSXDeliveryCount"));
|
||||
|
||||
Assert.assertTrue(rm.getJMSRedelivered());
|
||||
|
||||
tx.delistResource(res, XAResource.TMSUCCESS);
|
||||
|
||||
tx.delistResource(consumerSess.getXAResource(), XAResource.TMSUCCESS);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
|
||||
if (tx != null) {
|
||||
try {
|
||||
mgr.commit();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
if (xaConn != null) {
|
||||
xaConn.close();
|
||||
}
|
||||
|
||||
if (toResume != null) {
|
||||
try {
|
||||
mgr.resume(toResume);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Receiver implements Runnable {
|
||||
|
||||
MessageConsumer cons;
|
||||
|
||||
int numMessages;
|
||||
|
||||
int numRecoveries;
|
||||
|
||||
boolean failed;
|
||||
|
||||
Session sess;
|
||||
|
||||
String name;
|
||||
|
||||
Receiver(final String name,
|
||||
final Session sess,
|
||||
final MessageConsumer cons,
|
||||
final int numMessages,
|
||||
final int numRecoveries) {
|
||||
this.sess = sess;
|
||||
this.cons = cons;
|
||||
this.numMessages = numMessages;
|
||||
this.numRecoveries = numRecoveries;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Message lastMessage = null;
|
||||
for (int j = 0; j < numRecoveries; j++) {
|
||||
|
||||
for (int i = 0; i < numMessages; i++) {
|
||||
TextMessage tm = (TextMessage) cons.receive();
|
||||
lastMessage = tm;
|
||||
|
||||
if (tm == null) {
|
||||
failed = true;
|
||||
} else if (!tm.getText().equals("testing" + i)) {
|
||||
failed = true;
|
||||
} else if (tm.getIntProperty("JMSXDeliveryCount") != j + 1) {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
if (j != numRecoveries - 1) {
|
||||
sess.recover();
|
||||
}
|
||||
|
||||
}
|
||||
lastMessage.acknowledge();
|
||||
} catch (Exception e) {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyXAResource implements XAResource {
|
||||
|
||||
DummyXAResource() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit(final Xid arg0, final boolean arg1) throws XAException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(final Xid arg0, final int arg1) throws XAException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forget(final Xid arg0) throws XAException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransactionTimeout() throws XAException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameRM(final XAResource arg0) throws XAException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prepare(final Xid arg0) throws XAException {
|
||||
return XAResource.XA_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Xid[] recover(final int arg0) throws XAException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(final Xid arg0) throws XAException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTransactionTimeout(final int arg0) throws XAException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(final Xid arg0, final int arg1) throws XAException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,120 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.protocols.hornetq;
|
||||
|
||||
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 java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.Message;
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||
import org.apache.activemq.artemis.core.config.CoreQueueConfiguration;
|
||||
import org.apache.activemq.artemis.core.protocol.hornetq.client.HornetQClientProtocolManagerFactory;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||
import org.apache.activemq.artemis.jms.client.ActiveMQQueue;
|
||||
import org.apache.activemq.artemis.ra.recovery.RecoveryManager;
|
||||
import org.apache.activemq.artemis.service.extensions.xa.recovery.XARecoveryConfig;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* These tests attempt to mimic a legacy client without actually using a legacy versions of the client libraries.
|
||||
*/
|
||||
public class HornetQProtocolManagerTest extends ActiveMQTestBase {
|
||||
|
||||
ActiveMQServer server;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
server = createServer(createDefaultConfig(false)
|
||||
.setPersistenceEnabled(false)
|
||||
.clearAcceptorConfigurations()
|
||||
.addAcceptorConfiguration("legacy", "tcp://localhost:61616?protocols=HORNETQ")
|
||||
.addAcceptorConfiguration("corepr", "tcp://localhost:61617?protocols=CORE")
|
||||
.addQueueConfiguration(new CoreQueueConfiguration()
|
||||
.setName("testQueue")
|
||||
.setAddress("testQueue")
|
||||
.setRoutingType(RoutingType.ANYCAST)));
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLegacy() throws Exception {
|
||||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616?protocolManagerFactoryStr=" + HornetQClientProtocolManagerFactory.class.getName());
|
||||
connectionFactory.createConnection().close();
|
||||
ActiveMQConnectionFactory connectionFactory2 = new ActiveMQConnectionFactory("tcp://localhost:61617");
|
||||
connectionFactory2.createConnection().close();
|
||||
|
||||
RecoveryManager manager = new RecoveryManager();
|
||||
manager.register(connectionFactory, null, null, new ConcurrentHashMap<String, String>());
|
||||
manager.register(connectionFactory2, null, null, new ConcurrentHashMap<String, String>());
|
||||
|
||||
for (XARecoveryConfig resource : manager.getResources()) {
|
||||
try (ServerLocator locator = resource.createServerLocator();
|
||||
ClientSessionFactory factory = locator.createSessionFactory();
|
||||
ClientSession session = factory.createSession()) {
|
||||
// Nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** This test will use an ArtemisConnectionFactory with clientProtocolManager=*/
|
||||
@Test
|
||||
public void testLegacy2() throws Exception {
|
||||
// WORKAROUND: the 2.0.0 broker introduced addressing change and the 2.2.0 broker added compatibility for old
|
||||
// client libraries relying on the legacy prefixes. The new client being used in this test needs prefix explicitly.
|
||||
Queue queue = new ActiveMQQueue("jms.queue.testQueue");
|
||||
ActiveMQConnectionFactory connectionFactory = ActiveMQJMSClient.createConnectionFactory("tcp://localhost:61616?protocolManagerFactoryStr=" + HornetQClientProtocolManagerFactory.class.getName(), "legacy");
|
||||
Connection connection = connectionFactory.createConnection();
|
||||
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||
MessageProducer producer = session.createProducer(queue);
|
||||
|
||||
TextMessage message = session.createTextMessage("Test");
|
||||
for (int i = 0; i < 5; i++) {
|
||||
message.setStringProperty(Message.HDR_DUPLICATE_DETECTION_ID.toString(), "duplicate");
|
||||
producer.send(message);
|
||||
}
|
||||
|
||||
connection.start();
|
||||
MessageConsumer consumer = session.createConsumer(queue);
|
||||
TextMessage messageRec = (TextMessage) consumer.receive(5000);
|
||||
Assert.assertNotNull(messageRec);
|
||||
|
||||
Assert.assertEquals("Test", messageRec.getText());
|
||||
Assert.assertNull(consumer.receiveNoWait());
|
||||
connection.close();
|
||||
connectionFactory.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,333 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.activemq.artemis.tests.extras.protocols.hornetq;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.Message;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.hornetq.api.core.HornetQException;
|
||||
import org.hornetq.api.core.client.HornetQClient;
|
||||
import org.hornetq.utils.UUIDGenerator;
|
||||
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 HornetQProtocolTest extends ActiveMQTestBase {
|
||||
|
||||
protected ActiveMQServer server;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HornetQProtocolTest.class);
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, "" + 5445);
|
||||
params.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PROTOCOLS_PROP_NAME, "HORNETQ");
|
||||
TransportConfiguration transportConfig = new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params);
|
||||
|
||||
super.setUp();
|
||||
server = createServer(true, true);
|
||||
server.getConfiguration().getAcceptorConfigurations().add(transportConfig);
|
||||
LOG.info("Added connector {} to broker", "HornetQ");
|
||||
server.start();
|
||||
waitForServerToStart(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
org.hornetq.core.client.impl.ServerLocatorImpl.clearThreadPools();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessagePropertiesAreTransformedBetweenCoreAndHQProtocols() throws Exception {
|
||||
org.hornetq.api.core.client.ClientSession hqSession = createHQClientSession();
|
||||
ClientSession coreSession = createCoreClientSession();
|
||||
|
||||
// Create Queue
|
||||
String queueName = "test.hq.queue";
|
||||
hqSession.createQueue(queueName, queueName, true);
|
||||
|
||||
// HornetQ Client Objects
|
||||
hqSession.start();
|
||||
org.hornetq.api.core.client.ClientProducer hqProducer = hqSession.createProducer(queueName);
|
||||
org.hornetq.api.core.client.ClientConsumer hqConsumer = hqSession.createConsumer(queueName);
|
||||
|
||||
// Core Client Objects
|
||||
coreSession.start();
|
||||
ClientConsumer coreConsumer = coreSession.createConsumer(queueName);
|
||||
|
||||
// Check that HornetQ Properties are correctly converted to core properties.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
hqProducer.send(createHQTestMessage(hqSession));
|
||||
}
|
||||
|
||||
ClientMessage coreMessage1 = coreConsumer.receive(1000);
|
||||
System.err.println("Messages::==" + coreMessage1);
|
||||
assertTrue(coreMessage1.containsProperty(Message.HDR_DUPLICATE_DETECTION_ID));
|
||||
coreSession.close();
|
||||
|
||||
// Check that HornetQ Properties are correctly transformed from then to HornetQ properties
|
||||
org.hornetq.api.core.client.ClientMessage hqMessage1 = hqConsumer.receive(1000);
|
||||
assertTrue(hqMessage1.containsProperty(org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID));
|
||||
|
||||
hqSession.close();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateConsumerHQSelectorIsTransformed() throws Exception {
|
||||
try (org.hornetq.api.core.client.ClientSession hqSession = createHQClientSession()) {
|
||||
|
||||
// Create Queue
|
||||
String queueName = "test.hq.queue";
|
||||
hqSession.createQueue(queueName, queueName, true);
|
||||
|
||||
hqSession.start();
|
||||
|
||||
// Send message with UserID set
|
||||
org.hornetq.utils.UUID userID = UUIDGenerator.getInstance().generateUUID();
|
||||
try (org.hornetq.api.core.client.ClientProducer hqProducer = hqSession.createProducer(queueName)) {
|
||||
org.hornetq.api.core.client.ClientMessage message = createHQTestMessage(hqSession);
|
||||
message.setUserID(userID);
|
||||
hqProducer.send(message);
|
||||
}
|
||||
|
||||
// Verify that selector using AMQ field works
|
||||
verifyConsumerWithSelector(hqSession, queueName,
|
||||
String.format("AMQUserID = 'ID:%s'", userID.toString()), userID);
|
||||
|
||||
// Verify that selector using HornetQ field works
|
||||
verifyConsumerWithSelector(hqSession, queueName,
|
||||
String.format("HQUserID = 'ID:%s'", userID.toString()), userID);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateQueueHQFilterIsTransformed() throws Exception {
|
||||
testQueueWithHQFilter(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTemporaryQueueHQFilterIsTransformed() throws Exception {
|
||||
testQueueWithHQFilter(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeMessagesOverHornetQClients() throws Exception {
|
||||
org.hornetq.api.core.client.ClientSession hqSession = createHQClientSession();
|
||||
|
||||
// Create Queue
|
||||
String queueName = "test.hq.queue";
|
||||
hqSession.createQueue(queueName, queueName, true);
|
||||
|
||||
// HornetQ Client Objects
|
||||
hqSession.start();
|
||||
org.hornetq.api.core.client.ClientProducer hqProducer = hqSession.createProducer(queueName);
|
||||
org.hornetq.api.core.client.ClientConsumer hqConsumer = hqSession.createConsumer(queueName);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
org.hornetq.api.core.client.ClientMessage hqMessage = hqSession.createMessage(true);
|
||||
hqMessage.setBodyInputStream(ActiveMQTestBase.createFakeLargeStream(10 * 1024));
|
||||
hqProducer.send(hqMessage);
|
||||
}
|
||||
hqSession.commit();
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
org.hornetq.api.core.client.ClientMessage coreMessage1 = hqConsumer.receive(1000);
|
||||
coreMessage1.acknowledge();
|
||||
System.err.println("Messages::==" + coreMessage1);
|
||||
for (int j = 0; j < 10 * 1024; j++) {
|
||||
Assert.assertEquals(ActiveMQTestBase.getSamplebyte(j), coreMessage1.getBodyBuffer().readByte());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hqSession.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateIDPropertyWithHornetQProtocol() throws Exception {
|
||||
org.hornetq.api.core.client.ClientSession session = createHQClientSession();
|
||||
|
||||
String queueName = "test.hq.queue";
|
||||
session.createQueue(queueName, queueName, true);
|
||||
|
||||
org.hornetq.api.core.client.ClientProducer producer = session.createProducer(queueName);
|
||||
org.hornetq.api.core.client.ClientConsumer consumer = session.createConsumer(queueName);
|
||||
org.hornetq.api.core.client.ClientMessage message = session.createMessage(false);
|
||||
|
||||
String messageId = UUID.randomUUID().toString();
|
||||
message.putStringProperty(org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID.toString(), messageId);
|
||||
|
||||
session.start();
|
||||
producer.send(message);
|
||||
org.hornetq.api.core.client.ClientMessage m = consumer.receive(1000);
|
||||
assertTrue(m.containsProperty(org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID));
|
||||
assertNotNull(m);
|
||||
|
||||
producer.send(message);
|
||||
m = consumer.receive(1000);
|
||||
assertNull(m);
|
||||
|
||||
producer.send(message);
|
||||
m = consumer.receive(1000);
|
||||
assertNull(m);
|
||||
|
||||
session.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateIDPropertyWithHornetQAndCoreProtocol() throws Exception {
|
||||
org.hornetq.api.core.client.ClientSession hqSession = createHQClientSession();
|
||||
|
||||
String queueName = "test.hq.queue";
|
||||
hqSession.createQueue(queueName, queueName, true);
|
||||
|
||||
org.hornetq.api.core.client.ClientProducer hqProducer = hqSession.createProducer(queueName);
|
||||
org.hornetq.api.core.client.ClientMessage message = hqSession.createMessage(false);
|
||||
|
||||
String messageId = UUID.randomUUID().toString();
|
||||
message.putStringProperty(org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID.toString(), messageId);
|
||||
|
||||
ClientSession coreSession = createCoreClientSession();
|
||||
ClientConsumer coreConsumer = coreSession.createConsumer(queueName);
|
||||
|
||||
hqSession.start();
|
||||
coreSession.start();
|
||||
|
||||
hqProducer.send(message);
|
||||
Message m = coreConsumer.receive(1000);
|
||||
assertTrue(m.containsProperty(Message.HDR_DUPLICATE_DETECTION_ID));
|
||||
assertNotNull(m);
|
||||
|
||||
hqProducer.send(message);
|
||||
m = coreConsumer.receive(1000);
|
||||
assertNull(m);
|
||||
|
||||
hqProducer.send(message);
|
||||
m = coreConsumer.receive(1000);
|
||||
assertNull(m);
|
||||
}
|
||||
|
||||
private org.hornetq.api.core.client.ClientMessage createHQTestMessage(org.hornetq.api.core.client.ClientSession session) {
|
||||
org.hornetq.api.core.client.ClientMessage message = session.createMessage(true);
|
||||
String v = UUID.randomUUID().toString();
|
||||
message.putStringProperty(org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID.toString(), v);
|
||||
return message;
|
||||
}
|
||||
|
||||
private ClientMessage createCoreTestMessage(ClientSession session) {
|
||||
ClientMessage message = session.createMessage(true);
|
||||
String v = UUID.randomUUID().toString();
|
||||
message.putStringProperty(org.hornetq.api.core.Message.HDR_DUPLICATE_DETECTION_ID.toString(), v);
|
||||
return message;
|
||||
}
|
||||
|
||||
private org.hornetq.api.core.client.ClientSession createHQClientSession() throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("host", "localhost");
|
||||
map.put("port", 5445);
|
||||
|
||||
org.hornetq.api.core.client.ServerLocator serverLocator = HornetQClient.createServerLocatorWithoutHA(new org.hornetq.api.core.TransportConfiguration(org.hornetq.core.remoting.impl.netty.NettyConnectorFactory.class.getName(), map));
|
||||
org.hornetq.api.core.client.ClientSessionFactory sf = serverLocator.createSessionFactory();
|
||||
|
||||
return sf.createSession();
|
||||
}
|
||||
|
||||
private ClientSession createCoreClientSession() throws Exception {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("host", "localhost");
|
||||
map.put("port", 61616);
|
||||
|
||||
ServerLocator serverLocator = ActiveMQClient.createServerLocatorWithoutHA(new TransportConfiguration(NettyConnectorFactory.class.getName(), map));
|
||||
ClientSessionFactory sf = serverLocator.createSessionFactory();
|
||||
|
||||
return sf.createSession();
|
||||
}
|
||||
|
||||
private static void verifyConsumerWithSelector(org.hornetq.api.core.client.ClientSession hqSession, String queueName,
|
||||
String selector, org.hornetq.utils.UUID expectedUserID)
|
||||
throws HornetQException {
|
||||
try (org.hornetq.api.core.client.ClientConsumer hqConsumer =
|
||||
hqSession.createConsumer(queueName, selector, true)) {
|
||||
org.hornetq.api.core.client.ClientMessage message = hqConsumer.receive(1000);
|
||||
|
||||
Assert.assertNotNull(message);
|
||||
Assert.assertEquals(expectedUserID, message.getUserID());
|
||||
}
|
||||
}
|
||||
|
||||
private void testQueueWithHQFilter(boolean temporary) throws Exception {
|
||||
try (org.hornetq.api.core.client.ClientSession hqSession = createHQClientSession()) {
|
||||
|
||||
org.hornetq.utils.UUID userID = UUIDGenerator.getInstance().generateUUID();
|
||||
|
||||
// Create queue with filter
|
||||
String queueName = "test.hq.queue";
|
||||
String filter = String.format("HQUserID = 'ID:%s'", userID.toString());
|
||||
if (temporary) {
|
||||
hqSession.createTemporaryQueue(queueName, queueName, filter);
|
||||
} else {
|
||||
hqSession.createQueue(queueName, queueName, filter, true);
|
||||
}
|
||||
|
||||
hqSession.start();
|
||||
|
||||
// Send two messages with different UserIDs
|
||||
try (org.hornetq.api.core.client.ClientProducer hqProducer = hqSession.createProducer(queueName)) {
|
||||
org.hornetq.api.core.client.ClientMessage message = createHQTestMessage(hqSession);
|
||||
message.setUserID(userID);
|
||||
hqProducer.send(message);
|
||||
|
||||
message = createHQTestMessage(hqSession);
|
||||
message.setUserID(UUIDGenerator.getInstance().generateUUID());
|
||||
hqProducer.send(message);
|
||||
}
|
||||
|
||||
// Only the message matching the queue filter should be present
|
||||
try (org.hornetq.api.core.client.ClientConsumer hqConsumer =
|
||||
hqSession.createConsumer(queueName, true)) {
|
||||
org.hornetq.api.core.client.ClientMessage message = hqConsumer.receiveImmediate();
|
||||
|
||||
Assert.assertNotNull(message);
|
||||
Assert.assertEquals(userID, message.getUserID());
|
||||
|
||||
message = hqConsumer.receiveImmediate();
|
||||
Assert.assertNull(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
org.apache.activemq.artemis.tests.extras.jms.bridge.TransactionManagerLocatorImpl
|
|
@ -79,14 +79,6 @@
|
|||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>extra-tests</id>
|
||||
<modules>
|
||||
<!-- to run extra-tests you must define -DskipExtraTests=false
|
||||
or run it with the tests profile -->
|
||||
<module>extra-tests</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>jmh</id>
|
||||
<modules>
|
||||
|
@ -116,7 +108,6 @@
|
|||
<id>release</id>
|
||||
<modules>
|
||||
<module>activemq5-unit-tests</module>
|
||||
<module>extra-tests</module>
|
||||
<module>performance-jmh</module>
|
||||
</modules>
|
||||
<properties>
|
||||
|
|
Loading…
Reference in New Issue