Skip to content

HiveMQ Module

hivemq logo

Automatic starting HiveMQ docker containers for JUnit4 and JUnit5 tests. This enables testing MQTT client applications and integration testing of custom HiveMQ extensions.

Please make sure to check out the hivemq-docs for the Community Edition and the Enterprise Edition.

Using HiveMQ CE/EE

HiveMQ provides different editions of on Docker Hub:

Both editions can be used directly:

Using the Community Edition:

@Container
final HiveMQContainer hivemqCe = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3"))
    .withLogLevel(Level.DEBUG);

Using the Enterprise Edition:

@Container
final HiveMQContainer hivemqEe = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4"))
    .withLogLevel(Level.DEBUG);

Using a specific version is possible by using the tag:

@Container
final HiveMQContainer hivemqSpecificVersion = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce:2024.3"));

Test your MQTT 3 and MQTT 5 client application

Using an Mqtt-client (e.g. the HiveMQ-Mqtt-Client) you can start testing directly.

final Mqtt5BlockingClient client = Mqtt5Client
    .builder()
    .serverPort(hivemqCe.getMqttPort())
    .serverHost(hivemqCe.getHost())
    .buildBlocking();

client.connect();
client.disconnect();

Settings

There are several things that can be adjusted before container setup. The following example shows how to enable the Control Center (this is an enterprise feature), set the log level to DEBUG and load a HiveMQ-config-file from the classpath.

@Container
final HiveMQContainer hivemqEeWithControlCenter = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")
)
    .withLogLevel(Level.DEBUG)
    .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml"))
    .withControlCenter();

Note: The Control Center of HiveMQ can be accessed via the URL presented in the output of the starting container:

2021-09-10 10:35:53,511 INFO  - The HiveMQ Control Center is reachable under: http://localhost:55032

Please be aware that the Control Center is a feature of the enterprise edition of HiveMQ and thus only available with the enterprise image.


Testing HiveMQ extensions

Using the Extension SDK the functionality of all editions of HiveMQ can be extended. The HiveMQ module also supports testing your own custom extensions.

Wait Strategy

The raw HiveMQ module is built to wait for certain startup log messages to signal readiness. Since extensions are loaded dynamically they can be available a short while after the main container has started. We therefore provide custom wait conditions for HiveMQ Extensions:

The following will specify an extension to be loaded from src/test/resources/modifier-extension into the container and wait for an extension named 'My Extension Name' to be started:

@Container
final HiveMQContainer hivemqWithWaitStrategy = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")
)
    .withExtension(MountableFile.forClasspathResource("/modifier-extension"))
    .waitForExtension("Modifier Extension");

Next up we have an example for using an extension directly from the classpath and waiting directly on the extension:

final HiveMQExtension hiveMQEClasspathxtension = HiveMQExtension
    .builder()
    .id("extension-1")
    .name("my-extension")
    .version("1.0")
    .mainClass(MyExtensionWithSubclasses.class)
    .build();

@Container
final HiveMQContainer hivemqWithClasspathExtension = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3")
)
    .waitForExtension(hiveMQEClasspathxtension)
    .withExtension(hiveMQEClasspathxtension)
    .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml"));

Note Debugging extensions

Both examples contain .withDebugging() which enables remote debugging on the container. With debugging enabled you can start putting breakpoints right into your extensions.


Testing extensions using Gradle

In a Gradle based HiveMQ Extension project, testing is supported using the dedicated HiveMQ Extension Gradle Plugin.

The plugin adds an integrationTest task which executes tests from the integrationTest source set. - Integration test source files are defined in src/integrationTest. - Integration test dependencies are defined via the integrationTestImplementation, integrationTestRuntimeOnly, etc. configurations.

The integrationTest task builds the extension and unzips it to the build/hivemq-extension-test directory. The tests can then load the built extension into the HiveMQ Testcontainer.

@Container
final HiveMQContainer hivemqExtensionFromFilesystem = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")
)
    .withExtension(MountableFile.forHostPath("src/test/resources/modifier-extension"));

Enable/Disable an extension

It is possible to enable and disable HiveMQ extensions during runtime. Extensions can also be disabled on startup.


Note: that disabling or enabling of extension during runtime is only supported in HiveMQ 4 Enterprise Edition Containers.


The following example shows how to start a HiveMQ container with the extension called my-extension being disabled.

private final HiveMQExtension hiveMQExtension = HiveMQExtension
    .builder()
    .id("extension-1")
    .name("my-extension")
    .version("1.0")
    .disabledOnStartup(true)
    .mainClass(MyExtension.class)
    .build();

@Container
final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4"))
    .withExtension(hiveMQExtension);

The following test then proceeds to enable and then disable the extension:

@Test
void test_disable_enable_extension() throws Exception {
    hivemq.enableExtension(hiveMQExtension);
    hivemq.disableExtension(hiveMQExtension);
}

Enable/Disable an extension loaded from a folder

Extensions loaded from an extension folder during runtime can also be enabled/disabled on the fly. If the extension folder contains a DISABLED file, the extension will be disabled during startup.


Note: that disabling or enabling of extension during runtime is only supported in HiveMQ 4 Enterprise Edition Containers.


We first load the extension from the filesystem:

@Container
final HiveMQContainer hivemqExtensionFromFilesystem = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")
)
    .withExtension(MountableFile.forHostPath("src/test/resources/modifier-extension"));

Now we can enable/disable the extension using its name:

@Test
void test_disable_enable_extension_from_filesystem() throws Exception {
    hivemqExtensionFromFilesystem.disableExtension("Modifier Extension", "modifier-extension");
    hivemqExtensionFromFilesystem.enableExtension("Modifier Extension", "modifier-extension");
}

Remove prepackaged HiveMQ Extensions

Since HiveMQ's 4.4 release, HiveMQ Docker images come with the HiveMQ Extension for Kafka, the HiveMQ Enterprise Bridge Extension and the HiveMQ Enterprise Security Extension. These Extensions are disabled by default, but sometimes you my need to remove them before the container starts.

Removing all extension is as simple as:

@Container
final HiveMQContainer hivemqNoExtensions = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")
)
    .withoutPrepackagedExtensions();

A single extension (e.g. Kafka) can be removed as easily:

@Container
final HiveMQContainer hivemqNoKafkaExtension = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq4").withTag("4.7.4")
)
    .withoutPrepackagedExtensions("hivemq-kafka-extension");

Put files into the container

Put a file into HiveMQ home

final HiveMQContainer hivemqFileInHome = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3")
)
    .withFileInHomeFolder(
        MountableFile.forHostPath("src/test/resources/additionalFile.txt"),
        "/path/in/home/folder"
    );

Put files into extension home

@Container
final HiveMQContainer hivemqFileInExtensionHome = new HiveMQContainer(
    DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3")
)
    .withExtension(
        HiveMQExtension
            .builder()
            .id("extension-1")
            .name("my-extension")
            .version("1.0")
            .mainClass(MyExtension.class)
            .build()
    )
    .withFileInExtensionHomeFolder(
        MountableFile.forHostPath("src/test/resources/additionalFile.txt"),
        "extension-1",
        "/path/in/extension/home"
    );

Put license files into the container

@Container
final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3"))
    .withLicense(MountableFile.forHostPath("src/test/resources/myLicense.lic"))
    .withLicense(MountableFile.forHostPath("src/test/resources/myExtensionLicense.elic"));

Customize the Container further

Since the HiveMQContainer extends from Testcontainer's GenericContainer the container can be customized as desired.

Add to your project

Gradle

Add to build.gradle:

testImplementation 'org.testcontainers:hivemq:1.19.7'

Add to build.gradle.kts:

testImplementation("org.testcontainers:hivemq:1.19.7")

Maven

Add to pom.xml:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>hivemq</artifactId>
    <version>1.19.7</version>
    <scope>test</scope>
</dependency>