Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ActiveMQ and Artemis #7400

Merged
merged 7 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ body:
description: Which Testcontainers module are you using?
options:
- Core
- ActiveMQ
- Azure
- Cassandra
- Clickhouse
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/enhancement.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ body:
description: For which Testcontainers module does the enhancement proposal apply?
options:
- Core
- ActiveMQ
- Azure
- Cassandra
- Clickhouse
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ body:
description: Is this feature related to any of the existing modules?
options:
- Core
- ActiveMQ
- Azure
- Cassandra
- Clickhouse
Expand Down
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ updates:
open-pull-requests-limit: 10

# Explicit entry for each module
- package-ecosystem: "gradle"
directory: "/modules/activemq"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
- package-ecosystem: "gradle"
directory: "/modules/azure"
schedule:
Expand Down
4 changes: 4 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- gradle/wrapper/*
- gradlew
- gradlew.bat
"modules/activemq":
- changed-files:
- any-glob-to-any-file:
- modules/activemq/**/*
"modules/azure":
- changed-files:
- any-glob-to-any-file:
Expand Down
3 changes: 3 additions & 0 deletions .github/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ labels:
- name: help wanted
color: '#fef2c0'

- name: modules/activemq
color: '#006b75'

- name: modules/azure
color: '#006b75'

Expand Down
57 changes: 57 additions & 0 deletions docs/modules/activemq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# ActiveMQ

Testcontainers module for [ActiveMQ](https://hub.docker.com/r/apache/activemq-classic) and
[Artemis](https://hub.docker.com/r/apache/activemq-artemis).

## ActiveMQContainer's usage examples

You can start an ActiveMQ Classic container instance from any Java application by using:

<!--codeinclude-->
[Default ActiveMQ container](../../modules/activemq/src/test/java/org/testcontainers/activemq/ActiveMQContainerTest.java) inside_block:container
<!--/codeinclude-->

With custom credentials:

<!--codeinclude-->
[Setting custom credentials](../../modules/activemq/src/test/java/org/testcontainers/activemq/ActiveMQContainerTest.java) inside_block:settingCredentials
<!--/codeinclude-->

## ArtemisContainer's usage examples

You can start an ActiveMQ Artemis container instance from any Java application by using:

<!--codeinclude-->
[Default Artemis container](../../modules/activemq/src/test/java/org/testcontainers/activemq/ArtemisContainerTest.java) inside_block:container
<!--/codeinclude-->

With custom credentials:

<!--codeinclude-->
[Setting custom credentials](../../modules/activemq/src/test/java/org/testcontainers/activemq/ArtemisContainerTest.java) inside_block:settingCredentials
<!--/codeinclude-->

With anonymous login:

<!--codeinclude-->
[Allow anonymous login](../../modules/activemq/src/test/java/org/testcontainers/activemq/ArtemisContainerTest.java) inside_block:enableAnonymousLogin
<!--/codeinclude-->

## Adding this module to your project dependencies

Add the following dependency to your `pom.xml`/`build.gradle` file:

=== "Gradle"
```groovy
testImplementation "org.testcontainers:activemq:{{latest_version}}"
```

=== "Maven"
```xml
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>activemq</artifactId>
<version>{{latest_version}}</version>
<scope>test</scope>
</dependency>
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ nav:
- modules/databases/tidb.md
- modules/databases/trino.md
- modules/databases/yugabytedb.md
- modules/activemq.md
- modules/azure.md
- modules/consul.md
- modules/docker_compose.md
Expand Down
22 changes: 22 additions & 0 deletions modules/activemq/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
description = "Testcontainers :: ActiveMQ"

dependencies {
api project(':testcontainers')

testImplementation 'org.assertj:assertj-core:3.24.2'
testImplementation "org.apache.activemq:activemq-client-jakarta:5.18.2"
testImplementation "org.apache.activemq:artemis-jakarta-client:2.29.0"
}

test {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(11)
}
}

compileTestJava {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(11)
}
options.release.set(11)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.testcontainers.activemq;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;

import java.time.Duration;

/**
* Testcontainers implementation for Apache ActiveMQ.
* <p>
* Exposed ports:
* <ul>
* <li>Console: 8161</li>
* <li>TCP: 61616</li>
* <li>AMQP: 5672</li>
* <li>STOMP: 61613</li>
* <li>MQTT: 1883</li>
* <li>WS: 61614</li>
* </ul>
*/
public class ActiveMQContainer extends GenericContainer<ActiveMQContainer> {

private static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("apache/activemq-classic");

private static final int WEB_CONSOLE_PORT = 8161;

private static final int TCP_PORT = 61616;

private static final int AMQP_PORT = 5672;

private static final int STOMP_PORT = 61613;

private static final int MQTT_PORT = 1883;

private static final int WS_PORT = 61614;

private String username;

private String password;

public ActiveMQContainer(String image) {
this(DockerImageName.parse(image));
}

public ActiveMQContainer(DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE);

withExposedPorts(WEB_CONSOLE_PORT, TCP_PORT, AMQP_PORT, STOMP_PORT, MQTT_PORT, WS_PORT);
waitingFor(Wait.forLogMessage(".*Apache ActiveMQ.*started.*", 1).withStartupTimeout(Duration.ofMinutes(1)));
}

@Override
protected void configure() {
if (this.username != null) {
addEnv("ACTIVEMQ_CONNECTION_USER", this.username);
}
if (this.password != null) {
addEnv("ACTIVEMQ_CONNECTION_PASSWORD", this.password);
}
}

public ActiveMQContainer withUser(String username) {
this.username = username;
return this;
}

public ActiveMQContainer withPassword(String password) {
this.password = password;
return this;
}

public String getBrokerUrl() {
return String.format("tcp://%s:%s", getHost(), getMappedPort(TCP_PORT));
}

public String getUser() {
return this.username;
}

public String getPassword() {
return this.password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.testcontainers.activemq;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;

import java.time.Duration;

/**
* Testcontainers implementation for Apache ActiveMQ Artemis.
* <p>
* Exposed ports:
* <ul>
* <li>Console: 8161</li>
* <li>TCP: 61616</li>
* <li>HORNETQ: 5445</li>
* <li>AMQP: 5672</li>
* <li>STOMP: 61613</li>
* <li>MQTT: 1883</li>
* <li>WS: 61614</li>
* </ul>
*/
public class ArtemisContainer extends GenericContainer<ArtemisContainer> {

private static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("apache/activemq-artemis");

private static final int WEB_CONSOLE_PORT = 8161;

// CORE,MQTT,AMQP,HORNETQ,STOMP,OPENWIRE
private static final int TCP_PORT = 61616;

private static final int HORNETQ_STOMP_PORT = 5445;

private static final int AMQP_PORT = 5672;

private static final int STOMP_PORT = 61613;

private static final int MQTT_PORT = 1883;

private static final int WS_PORT = 61614;

private String username = "artemis";

private String password = "artemis";

public ArtemisContainer(String image) {
this(DockerImageName.parse(image));
}

public ArtemisContainer(DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE);

withExposedPorts(WEB_CONSOLE_PORT, TCP_PORT, HORNETQ_STOMP_PORT, AMQP_PORT, STOMP_PORT, MQTT_PORT, WS_PORT);
waitingFor(Wait.forLogMessage(".*HTTP Server started.*", 1).withStartupTimeout(Duration.ofMinutes(1)));
}

@Override
protected void configure() {
withEnv("ARTEMIS_USER", this.username);
withEnv("ARTEMIS_PASSWORD", this.password);
}

public ArtemisContainer withUser(String username) {
this.username = username;
return this;
}

public ArtemisContainer withPassword(String password) {
this.password = password;
return this;
}

public String getBrokerUrl() {
return String.format("tcp://%s:%s", getHost(), getMappedPort(TCP_PORT));
}

public String getUser() {
return getEnvMap().get("ARTEMIS_USER");
}

public String getPassword() {
return getEnvMap().get("ARTEMIS_PASSWORD");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.testcontainers.activemq;

import jakarta.jms.Connection;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.Destination;
import jakarta.jms.JMSException;
import jakarta.jms.MessageConsumer;
import jakarta.jms.MessageProducer;
import jakarta.jms.Session;
import jakarta.jms.TextMessage;
import lombok.SneakyThrows;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class ActiveMQContainerTest {

@Test
public void test() throws JMSException {
try ( // container {
ActiveMQContainer activemq = new ActiveMQContainer("apache/activemq-classic:5.18.3")
// }
) {
activemq.start();

assertThat(activemq.getUser()).isNull();
assertThat(activemq.getPassword()).isNull();
assertFunctionality(activemq, false);
}
}

@Test
public void customCredentials() {
try (
// settingCredentials {
ActiveMQContainer activemq = new ActiveMQContainer("apache/activemq-classic:5.18.3")
.withUser("testcontainers")
.withPassword("testcontainers")
// }
) {
activemq.start();

assertThat(activemq.getUser()).isEqualTo("testcontainers");
assertThat(activemq.getPassword()).isEqualTo("testcontainers");
assertFunctionality(activemq, true);
}
}

@SneakyThrows
private void assertFunctionality(ActiveMQContainer activemq, boolean useCredentials) {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(activemq.getBrokerUrl());
Connection connection;
if (useCredentials) {
connection = connectionFactory.createConnection(activemq.getUser(), activemq.getPassword());
} else {
connection = connectionFactory.createConnection();
}
connection.start();

Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

Destination destination = session.createQueue("test-queue");
MessageProducer producer = session.createProducer(destination);

String contentMessage = "Testcontainers";
TextMessage message = session.createTextMessage(contentMessage);
producer.send(message);

MessageConsumer consumer = session.createConsumer(destination);
TextMessage messageReceived = (TextMessage) consumer.receive();
assertThat(messageReceived.getText()).isEqualTo(contentMessage);
}
}
Loading
Loading