Skip to content

Commit bfb8cec

Browse files
Yannick Webercodepitbull
andauthored
New Module: HiveMQ (#4797)
Co-authored-by: Jochen Mader <[email protected]>
1 parent 71a073b commit bfb8cec

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2598
-0
lines changed

.github/dependabot.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ updates:
5757
schedule:
5858
interval: "monthly"
5959
open-pull-requests-limit: 10
60+
- package-ecosystem: "gradle"
61+
directory: "/modules/hivemq"
62+
schedule:
63+
interval: "monthly"
64+
open-pull-requests-limit: 10
6065
- package-ecosystem: "gradle"
6166
directory: "/modules/influxdb"
6267
schedule:
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.testcontainers.containers.wait.strategy;
2+
3+
import org.testcontainers.DockerClientFactory;
4+
import org.testcontainers.containers.ContainerLaunchException;
5+
import org.testcontainers.containers.output.OutputFrame;
6+
import org.testcontainers.containers.output.WaitingConsumer;
7+
import org.testcontainers.utility.LogUtils;
8+
9+
import java.util.Map;
10+
import java.util.concurrent.ConcurrentHashMap;
11+
import java.util.concurrent.TimeUnit;
12+
import java.util.concurrent.TimeoutException;
13+
import java.util.function.Predicate;
14+
15+
/**
16+
* This is a wait strategy to wait for multiple log patterns.
17+
* The wait strategy will continue when every log pattern is matched at least once.
18+
*/
19+
public class MultiLogMessageWaitStrategy extends AbstractWaitStrategy {
20+
21+
private final ConcurrentHashMap<String, Boolean> regexes = new ConcurrentHashMap<>();
22+
23+
@Override
24+
protected void waitUntilReady() {
25+
WaitingConsumer waitingConsumer = new WaitingConsumer();
26+
LogUtils.followOutput(DockerClientFactory.instance().client(), waitStrategyTarget.getContainerId(), waitingConsumer);
27+
28+
Predicate<OutputFrame> waitPredicate = outputFrame -> {
29+
if (regexes.isEmpty()) {
30+
return true;
31+
}
32+
regexes.entrySet().forEach(regexHasMatched -> {
33+
final boolean matched = outputFrame.getUtf8String().matches("(?s)" + regexHasMatched.getKey());
34+
if (matched) {
35+
regexHasMatched.setValue(true);
36+
}
37+
});
38+
return regexes.values().stream().reduce(Boolean::logicalAnd).orElse(true);
39+
};
40+
41+
try {
42+
waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, 1);
43+
} catch (TimeoutException e) {
44+
throw new ContainerLaunchException("Timed out waiting for log output matching '" + regexes + "'");
45+
}
46+
}
47+
48+
public MultiLogMessageWaitStrategy withRegEx(final String regEx) {
49+
regexes.put(regEx, false);
50+
return this;
51+
}
52+
53+
public MultiLogMessageWaitStrategy reset() {
54+
for (final Map.Entry<String, Boolean> stringBooleanEntry : regexes.entrySet()) {
55+
stringBooleanEntry.setValue(false);
56+
}
57+
return this;
58+
}
59+
}

docs/modules/hivemq.md

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# HiveMQ Module
2+
3+
<img src="../modules_logos/hivemq-module.png" alt="drawing" width="800"/>
4+
5+
Automatic starting HiveMQ docker containers for JUnit4 and JUnit5 tests.
6+
This enables testing MQTT client applications and integration testing of custom HiveMQ extensions.
7+
8+
- Community forum: https://community.hivemq.com/
9+
- HiveMQ website: https://www.hivemq.com/
10+
- MQTT resources:
11+
- [MQTT Essentials](https://www.hivemq.com/mqtt-essentials/)
12+
- [MQTT 5 Essentials](https://www.hivemq.com/mqtt-5/)
13+
14+
Please make sure to check out the hivemq-docs for the [Community Edition](https://github.com/hivemq/hivemq-community-edition/wiki/)
15+
and the [Enterprise Edition](https://www.hivemq.com/docs/hivemq/4.7/user-guide/).
16+
17+
## Using HiveMQ CE/EE
18+
19+
HiveMQ provides different editions of on [Docker Hub](https://hub.docker.com/u/hivemq):
20+
21+
- the open source [Community Edition](https://github.com/hivemq/hivemq-community-edition) which
22+
is published as *hivemq/hivemq-ce*.
23+
- the [Enterprise Edition](https://www.hivemq.com/docs/hivemq/4.7/user-guide/) which is published as *hivemq/hivemq4*.
24+
25+
Both editions can be used directly:
26+
27+
Using the Community Edition:
28+
<!--codeinclude-->
29+
[Community Edition HiveMQ image](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:ceVersion
30+
<!--/codeinclude-->
31+
32+
Using the Enterprise Edition:
33+
<!--codeinclude-->
34+
[Enterprise Edition HiveMQ image](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:eeVersion
35+
<!--/codeinclude-->
36+
37+
Using a specifc version is possible by using the tag:
38+
<!--codeinclude-->
39+
[Specific HiveMQ Version](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:specificVersion
40+
<!--/codeinclude-->
41+
42+
## Test your MQTT 3 and MQTT 5 client application
43+
44+
Using an Mqtt-client (e.g. the [HiveMQ-Mqtt-Client](https://github.com/hivemq/hivemq-mqtt-client)) you can start
45+
testing directly.
46+
47+
<!--codeinclude-->
48+
[MQTT5 Client](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:mqtt5client
49+
<!--/codeinclude-->
50+
51+
## Settings
52+
53+
There are several things that can be adjusted before container setup.
54+
The following example shows how to enable the Control Center (this is an enterprise feature), set the log level to DEBUG
55+
and load a HiveMQ-config-file from the classpath.
56+
57+
<!--codeinclude-->
58+
[Config Examples](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:eeVersionWithControlCenter
59+
<!--/codeinclude-->
60+
61+
---
62+
**Note:**
63+
The Control Center of HiveMQ can be accessed via the URL presented in the output of the starting container:
64+
65+
```
66+
2021-09-10 10:35:53,511 INFO - The HiveMQ Control Center is reachable under: http://localhost:55032
67+
```
68+
69+
Please be aware that the Control Center is a feature of the enterprise edition of HiveMQ and thus only available with
70+
the enterprise image.
71+
72+
---
73+
74+
## Testing HiveMQ extensions
75+
76+
Using the [Extension SDK](https://github.com/hivemq/hivemq-extension-sdk) the functionality of all editions of HiveMQ
77+
can be extended.
78+
The HiveMQ module also supports testing your own custom extensions.
79+
80+
### Wait Strategy
81+
82+
The raw HiveMQ module is built to wait for certain startup log messages to signal readiness.
83+
Since extensions are loaded dynamically they can be available a short while after the main container has started.
84+
We therefore provide custom wait conditions for HiveMQ Extensions:
85+
86+
The following will specify an extension to be loaded from **src/test/resources/modifier-extension** into the container and
87+
wait for an extension named **'My Extension Name'** to be started:
88+
89+
<!--codeinclude-->
90+
[Custom Wait Strategy](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java) inside_block:waitStrategy
91+
<!--/codeinclude-->
92+
93+
Next up we have an example for using an extension directly from the classpath and waiting directly on the extension:
94+
95+
<!--codeinclude-->
96+
[Extension from Classpath](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java) inside_block:extensionClasspath
97+
<!--/codeinclude-->
98+
99+
---
100+
**Note** Debugging extensions
101+
102+
Both examples contain ```.withDebugging()``` which enables remote debugging on the container.
103+
With debugging enabled you can start putting breakpoints right into your extensions.
104+
105+
---
106+
107+
### Testing extensions using Gradle
108+
109+
In a Gradle based HiveMQ Extension project, testing is supported using the dedicated [HiveMQ Extension Gradle Plugin](https://github.com/hivemq/hivemq-extension-gradle-plugin/README.md).
110+
111+
The plugin adds an `integrationTest` task which executes tests from the `integrationTest` source set.
112+
- Integration test source files are defined in `src/integrationTest`.
113+
- Integration test dependencies are defined via the `integrationTestImplementation`, `integrationTestRuntimeOnly`, etc. configurations.
114+
115+
The `integrationTest` task builds the extension and unzips it to the `build/hivemq-extension-test` directory.
116+
The tests can then load the built extension into the HiveMQ Testcontainer.
117+
118+
<!--codeinclude-->
119+
[Extension from filesystem](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:startFromFilesystem
120+
<!--/codeinclude-->
121+
122+
### Enable/Disable an extension
123+
124+
It is possible to enable and disable HiveMQ extensions during runtime. Extensions can also be disabled on startup.
125+
126+
---
127+
**Note**: that disabling or enabling of extension during runtime is only supported in HiveMQ 4 Enterprise Edition Containers.
128+
129+
---
130+
131+
The following example shows how to start a HiveMQ container with the extension called **my-extension** being disabled.
132+
133+
134+
<!--codeinclude-->
135+
[Disable Extension at startup](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:startDisabled
136+
<!--/codeinclude-->
137+
138+
The following test then proceeds to enable and then disable the extension:
139+
140+
<!--codeinclude-->
141+
[Enable/Disable extension at runtime](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:runtimeEnable
142+
<!--/codeinclude-->
143+
144+
## Enable/Disable an extension loaded from a folder
145+
146+
Extensions loaded from an extension folder during runtime can also be enabled/disabled on the fly.
147+
If the extension folder contains a DISABLED file, the extension will be disabled during startup.
148+
149+
---
150+
**Note**: that disabling or enabling of extension during runtime is only supported in HiveMQ 4 Enterprise Edition Containers.
151+
152+
---
153+
154+
We first load the extension from the filesytem:
155+
<!--codeinclude-->
156+
[Extension from filesystem](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:startFromFilesystem
157+
<!--/codeinclude-->
158+
159+
Now we can enable/disable the extension using its name:
160+
161+
<!--codeinclude-->
162+
[Enable/Disable extension at runtime](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:runtimeEnableFilesystem
163+
<!--/codeinclude-->
164+
165+
### Remove prepackaged HiveMQ Extensions
166+
167+
Since HiveMQ's 4.4 release, HiveMQ Docker images come with the HiveMQ Extension for Kafka, the HiveMQ Enterprise Bridge Extension
168+
and the HiveMQ Enterprise Security Extension.
169+
These Extensions are disabled by default, but sometimes you my need to remove them before the container starts.
170+
171+
Removing all extension is as simple as:
172+
173+
<!--codeinclude-->
174+
[Remove all extensions](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:noExtensions
175+
<!--/codeinclude-->
176+
177+
A single extension (e.g. Kafka) can be removed as easily:
178+
<!--codeinclude-->
179+
[Remove a specific extension](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:noKafkaExtension
180+
<!--/codeinclude-->
181+
182+
## Put files into the container
183+
184+
### Put a file into HiveMQ home
185+
186+
<!--codeinclude-->
187+
[Put file into HiveMQ home](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java) inside_block:hivemqHome
188+
<!--/codeinclude-->
189+
190+
### Put files into extension home
191+
192+
<!--codeinclude-->
193+
[Put file into HiveMQ-Extension home](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java) inside_block:extensionHome
194+
<!--/codeinclude-->
195+
196+
### Put license files into the container
197+
198+
<!--codeinclude-->
199+
[Put license file into the HiveMQ container](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java) inside_block:withLicenses
200+
<!--/codeinclude-->
201+
202+
203+
### Customize the Container further
204+
205+
Since the `HiveMQContainer` extends from [Testcontainer's](https://github.com/testcontainers) `GenericContainer` the container
206+
can be customized as desired.
207+
208+
## Add to your project
209+
210+
### Gradle
211+
212+
Add to `build.gradle`:
213+
214+
````groovy
215+
testImplementation 'org.testcontainers:hivemq:{{latest_version}}'
216+
````
217+
218+
Add to `build.gradle.kts`:
219+
220+
````kotlin
221+
testImplementation("org.testcontainers:hivemq:{{latest_version}}")
222+
````
223+
224+
### Maven
225+
226+
Add to `pom.xml`:
227+
228+
```xml
229+
<dependency>
230+
<groupId>org.testcontainers</groupId>
231+
<artifactId>hivemq</artifactId>
232+
<version>{{latest_version}}</version>
233+
<scope>test</scope>
234+
</dependency>
235+
```
161 KB
Loading

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ nav:
6767
- modules/docker_compose.md
6868
- modules/elasticsearch.md
6969
- modules/gcloud.md
70+
- modules/hivemq.md
7071
- modules/k3s.md
7172
- modules/kafka.md
7273
- modules/localstack.md

modules/hivemq/build.gradle

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
description = "TestContainers :: HiveMQ"
2+
3+
dependencies {
4+
api(project(":testcontainers"))
5+
api("org.jetbrains:annotations:23.0.0")
6+
7+
shaded("org.apache.commons:commons-lang3:3.12.0")
8+
shaded("commons-io:commons-io:2.11.0")
9+
shaded("org.javassist:javassist:3.28.0-GA")
10+
shaded("org.jboss.shrinkwrap:shrinkwrap-api:1.2.6")
11+
shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6")
12+
shaded("net.lingala.zip4j:zip4j:2.9.1")
13+
14+
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
15+
testImplementation(project(":junit-jupiter"))
16+
testImplementation("com.hivemq:hivemq-extension-sdk:4.7.3")
17+
testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0")
18+
testImplementation("org.apache.httpcomponents:httpclient:4.5.13")
19+
testImplementation("ch.qos.logback:logback-classic:1.2.10")
20+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
21+
}
22+
23+
test {
24+
useJUnitPlatform()
25+
testLogging {
26+
events "passed", "skipped", "failed"
27+
}
28+
javaLauncher = javaToolchains.launcherFor {
29+
languageVersion = JavaLanguageVersion.of(11)
30+
}
31+
}
32+
33+
compileTestJava {
34+
javaCompiler = javaToolchains.compilerFor {
35+
languageVersion = JavaLanguageVersion.of(11)
36+
}
37+
}

0 commit comments

Comments
 (0)