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
|
- name: Build Main
|
||||||
run: |
|
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)
|
- name: Build Examples (JDK11 / -Prelease)
|
||||||
if: matrix.java == '11'
|
if: matrix.java == '11'
|
||||||
|
|
|
@ -16,11 +16,10 @@ before_install:
|
||||||
- rm -rf $HOME/.m2/repository/org/apache/activemq/artemis-*
|
- rm -rf $HOME/.m2/repository/org/apache/activemq/artemis-*
|
||||||
|
|
||||||
# use 'install' so smoke-tests will work
|
# 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
|
# By setting anything to org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory.DISABLED we are disabling libaio loading on the testsuite
|
||||||
script:
|
script:
|
||||||
- set -e
|
- 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
|
- cd examples
|
||||||
- mvn -s ../.github/maven-settings.xml verify -P${EXAMPLES_PROFILE} -B -q
|
- 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.
|
is run the tests with `jacoco` maven profile.
|
||||||
|
|
||||||
```
|
```
|
||||||
mvn test -Ptests,extra-tests,jacoco
|
mvn test -Ptests,jacoco
|
||||||
```
|
```
|
||||||
|
|
||||||
## Generate JaCoCo reports
|
## 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/)
|
builds are running they can be reasonably confident. Currently the [PR build](https://builds.apache.org/job/ActiveMQ-Artemis-PR-Build/)
|
||||||
runs this command:
|
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
|
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.
|
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
|
# specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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 jacoco:merge -N -Pjacoco
|
||||||
mvn verify -Pjacoco-generate-report -DskipTests
|
mvn verify -Pjacoco-generate-report -DskipTests
|
||||||
|
|
|
@ -16,4 +16,4 @@
|
||||||
# specific language governing permissions and limitations
|
# specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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>
|
</build>
|
||||||
|
|
||||||
<profiles>
|
<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>
|
<profile>
|
||||||
<id>jmh</id>
|
<id>jmh</id>
|
||||||
<modules>
|
<modules>
|
||||||
|
@ -116,7 +108,6 @@
|
||||||
<id>release</id>
|
<id>release</id>
|
||||||
<modules>
|
<modules>
|
||||||
<module>activemq5-unit-tests</module>
|
<module>activemq5-unit-tests</module>
|
||||||
<module>extra-tests</module>
|
|
||||||
<module>performance-jmh</module>
|
<module>performance-jmh</module>
|
||||||
</modules>
|
</modules>
|
||||||
<properties>
|
<properties>
|
||||||
|
|
Loading…
Reference in New Issue