artemis Posts

Creating an Embeddable JMS Server using Artemis for Unit Testing

In this blog now we are trying to implement an embeddable JMS server for doing testing in Java. Embeddable JMS server is needed to reduce the dependency to a third party, in this case is JMS provider like ActiveMQ, and it is very lightweight therefore we can run it very fast and in multiple times. It is also needed for integration test to see whether our code can integrate smoothly with others. For this scenario im using JUnit 5, which is perhaps the latest version of JUnit at this time.

So lets start with a pom file, for describing what libraries are needed to this. For this example, im using snowdrop bom from Red Hat.

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>embeddable-artemis-mq-junit5</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <spring-boot.version>2.1.6.RELEASE</spring-boot.version>
        <spring-boot-bom.version>2.3.6.Final-redhat-00001</spring-boot-bom.version>
        <junit-version>5.7.2</junit-version>

        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!-- Exclude the Tomcat dependency -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-artemis</artifactId>
        </dependency>

        <!-- artemis -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-server</artifactId>
            <version>2.12.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>artemis-core-client</artifactId>
            <version>2.12.0</version>
        </dependency>
        <!-- artemis -->

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-commons</artifactId>
            <version>1.7.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>dev.snowdrop</groupId>
                <artifactId>snowdrop-dependencies</artifactId>
                <version>${spring-boot-bom.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.1.3.RELEASE</version>
                <configuration>
                    <mainClass>com.edw.Main</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
            </plugin>

        </plugins>
    </build>

</project>

One of the most important thing is we need to create an xml file called broker.xml. The purpose is to store configuration for our embeddable JMS, one of the most important configuration would be the roles and type of privileges.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq ../../../../src/schema/artemis-configuration.xsd">
    <core xmlns="urn:activemq:core">
        <bindings-directory>./data/messaging/bindings</bindings-directory>
        <journal-directory>./data/messaging/journal</journal-directory>
        <large-messages-directory>./data/messaging/largemessages</large-messages-directory>
        <paging-directory>./data/messaging/paging</paging-directory>
        <management-notification-address>notificationsTopic</management-notification-address>
        <acceptors>
            <acceptor name="netty">tcp://localhost:61616</acceptor>
        </acceptors>

        <max-disk-usage>100</max-disk-usage>

        <security-settings>
            <security-setting match="#">
                <permission roles="admin" type="createDurableQueue"/>
                <permission roles="admin" type="deleteDurableQueue"/>
                <permission roles="admin" type="createNonDurableQueue"/>
                <permission roles="admin" type="deleteNonDurableQueue"/>
                <permission roles="admin" type="consume"/>
                <permission roles="admin" type="browse"/>
                <permission roles="admin" type="send"/>
                <permission roles="admin" type="createAddress"/>
                <permission roles="admin" type="deleteAddress"/>
            </security-setting>
        </security-settings>
    </core>
</configuration>

Last step is creating a simple java files, dont forget to create a user and give them a role based on the defined roles in broker.xml.

package com.edw.jms;

import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class JMSServiceTest {

    @Autowired
    private JMSService jmsService;

    private static EmbeddedActiveMQ embedded = new EmbeddedActiveMQ();

    @BeforeAll
    public static void before() throws Exception {
        SecurityConfiguration configuration = new SecurityConfiguration();
        configuration.addUser("user", "password");
        configuration.addRole("user", "admin");

        final ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager (InVMLoginModule.class.getName(), configuration);

        embedded.setSecurityManager(securityManager);
        embedded.start();
    }

    @AfterAll
    public static void after() throws Exception {
        embedded.stop();
    }

    /**
     * send message to local embeddable jms, and read it.
     *
     * @throws Exception
     */
    @Test
    @DisplayName("This test is to check if a valid message is being sent to MQ thru JMS is success, and we can read it after")
    public void sendJMSData_expectSuccess() throws Exception {
        Assertions.assertDoesNotThrow(()-> jmsService.send("trysmething"));
        Thread.sleep(2000);
        Assertions.assertEquals("trysmething", jmsService.read());
    }

}

Run the test cases by using below command,

$ mvn clean package -s settings.xml

And for the full code for this article can be found here,

https://github.com/edwin/embeddable-artemis-server-and-junit-5

Creating a Red Hat AMQ Broker or ActiveMQ Artemis Stress Testing using JMeter

Red Hat AMQ Broker (or its Opensource version, Apache ActiveMQ), is a flexible, high-performance messaging platform that delivers information reliably, enabling real-time integration. It can handle lot of messages at the same time, up to 21-22thousands messages/seconds, as per below link.

https://activemq.apache.org/performance.html

In this article, im trying to try and see how many transaction can one AMQ handle by using a JMeter script. Lets start by installing ActiveMQ Artemis from docker,

docker run -it --rm \
  -p 8161:8161 \
  -p 61616:61616 \
  -e ARTEMIS_USERNAME=admin \
  -e ARTEMIS_PASSWORD=password \
  vromero/activemq-artemis

Next step is downloading JMeter, and creating a test plan. But first, we need to download artemis-jms-client first and put it on our JMeter_FOLDER/lib/ext folder.

Next is opening our JMeter and create a thread group, for this example im creating 2 loops , with 2 threads each.

Create JMS Publisher, with below parameter

Initial Context Factory : org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
Provider URL : tcp://localhost:61616
User Authorization : admin
Password Authorization : password
Connection Factory : ConnectionFactory
Destination : dynamicQueues/queue01

JMSCorrelationID : ${__counter(FALSE,)} with class of value java.lang.String


Create JMS Subscriber, with below parameter

Initial Context Factory : org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
Provider URL : tcp://localhost:61616
User Authorization : admin
Password Authorization : password
Connection Factory : ConnectionFactory
Destination : dynamicQueues/queue01


Run JMeter and we can see the result on both Result Tree and Summary Report,

Have fun stresstesting AMQ 🙂