From 59cd2dbbc9f33c7d91849d98e90d085abbc32429 Mon Sep 17 00:00:00 2001 From: yweber Date: Tue, 23 Nov 2021 11:21:36 +0100 Subject: [PATCH 01/30] moved hivemq testcontainer to testcontainers-java --- modules/hivemq/.gitignore | 1 + modules/hivemq/build.gradle.kts | 38 + modules/hivemq/gradle.properties | 26 + .../hivemq/GradleHiveMQExtensionSupplier.java | 179 +++++ .../hivemq/HiveMQContainer.java | 665 ++++++++++++++++++ .../hivemq/HiveMQExtension.java | 168 +++++ .../hivemq/MavenHiveMQExtensionSupplier.java | 111 +++ .../hivemq/MultiLogMessageWaitStrategy.java | 78 ++ .../org/testcontainers/hivemq/PathUtil.java | 44 ++ .../hivemq/ContainerWithControlCenterIT.java | 51 ++ .../hivemq/ContainerWithCustomConfigIT.java | 61 ++ ...ContainerWithExtensionFromDirectoryIT.java | 58 ++ .../hivemq/ContainerWithExtensionIT.java | 56 ++ .../ContainerWithExtensionSubclassIT.java | 50 ++ .../ContainerWithFileInExtensionHomeIT.java | 93 +++ .../hivemq/ContainerWithFileInHomeIT.java | 90 +++ .../ContainerWithGradleExtensionIT.java | 46 ++ .../hivemq/ContainerWithLicenseIT.java | 93 +++ .../hivemq/ContainerWithMavenExtensionIT.java | 49 ++ .../ContainerWithoutPlatformExtensionsIT.java | 153 ++++ .../hivemq/CreateFileInCopiedDirectoryIT.java | 108 +++ .../CreateFileInExtensionDirectoryIT.java | 90 +++ ...DisableEnableExtensionFromDirectoryIT.java | 55 ++ .../hivemq/DisableEnableExtensionIT.java | 64 ++ .../hivemq/DisableEnableMavenExtensionIT.java | 59 ++ .../hivemq/HiveMQTestContainerCore.java | 98 +++ .../testcontainers/hivemq/PathUtilTest.java | 61 ++ .../hivemq/util/MyExtension.java | 55 ++ .../util/MyExtensionWithSubclasses.java | 44 ++ .../hivemq/util/PublishModifier.java | 34 + .../hivemq/util/TestPublishModifiedUtil.java | 66 ++ .../src/test/resources/additionalFile.txt | 16 + modules/hivemq/src/test/resources/config.xml | 32 + .../resources/gradle-extension/build.gradle | 32 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 21 + .../test/resources/gradle-extension/gradlew | 0 .../resources/gradle-extension/gradlew.bat | 105 +++ .../gradle-extension/settings.gradle | 21 + .../src/main/java/com/hivemq/MyExtension.java | 56 ++ .../src/test/resources/logback-test.xml | 39 + .../resources/maven-extension/assembly.xml | 39 + .../test/resources/maven-extension/pom.xml | 104 +++ .../src/main/java/com/hivemq/MyExtension.java | 56 ++ ...com.hivemq.extension.sdk.api.ExtensionMain | 1 + .../src/main/resources/hivemq-extension.xml | 25 + .../hivemq-extension.xml | 25 + .../modifier-extension-1.0-SNAPSHOT.jar | Bin 0 -> 102179 bytes .../modifier-extension/hivemq-extension.xml | 25 + .../modifier-extension-1.0-SNAPSHOT.jar | Bin 0 -> 102179 bytes .../test/resources/myExtensionLicense.elic | 0 .../hivemq/src/test/resources/myLicense.lic | 0 52 files changed, 3441 insertions(+) create mode 100644 modules/hivemq/.gitignore create mode 100644 modules/hivemq/build.gradle.kts create mode 100644 modules/hivemq/gradle.properties create mode 100644 modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java create mode 100644 modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java create mode 100644 modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java create mode 100644 modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java create mode 100644 modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java create mode 100755 modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java create mode 100755 modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java create mode 100755 modules/hivemq/src/test/resources/additionalFile.txt create mode 100755 modules/hivemq/src/test/resources/config.xml create mode 100644 modules/hivemq/src/test/resources/gradle-extension/build.gradle create mode 100644 modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.jar create mode 100644 modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties create mode 100644 modules/hivemq/src/test/resources/gradle-extension/gradlew create mode 100644 modules/hivemq/src/test/resources/gradle-extension/gradlew.bat create mode 100644 modules/hivemq/src/test/resources/gradle-extension/settings.gradle create mode 100644 modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java create mode 100644 modules/hivemq/src/test/resources/logback-test.xml create mode 100644 modules/hivemq/src/test/resources/maven-extension/assembly.xml create mode 100644 modules/hivemq/src/test/resources/maven-extension/pom.xml create mode 100644 modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java create mode 100644 modules/hivemq/src/test/resources/maven-extension/src/main/resources/META-INF/services/com.hivemq.extension.sdk.api.ExtensionMain create mode 100644 modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml create mode 100755 modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml create mode 100644 modules/hivemq/src/test/resources/modifier-extension-wrong-name/modifier-extension-1.0-SNAPSHOT.jar create mode 100755 modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml create mode 100644 modules/hivemq/src/test/resources/modifier-extension/modifier-extension-1.0-SNAPSHOT.jar create mode 100755 modules/hivemq/src/test/resources/myExtensionLicense.elic create mode 100755 modules/hivemq/src/test/resources/myLicense.lic diff --git a/modules/hivemq/.gitignore b/modules/hivemq/.gitignore new file mode 100644 index 00000000000..6a3417b8d9d --- /dev/null +++ b/modules/hivemq/.gitignore @@ -0,0 +1 @@ +/out/ diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts new file mode 100644 index 00000000000..e190d3e0f5e --- /dev/null +++ b/modules/hivemq/build.gradle.kts @@ -0,0 +1,38 @@ +description = "Core API for testing HiveMQ Extensions and Java MQTT Applications." + +dependencies { + api(project(":testcontainers")) + api("org.jetbrains:annotations:${property("annotations.version")}") + + implementation("org.apache.commons:commons-lang3:${property("commons-lang.version")}") + implementation("com.google.guava:guava:${property("guava.version")}") + implementation("commons-io:commons-io:${property("commons-io.version")}") + implementation("org.javassist:javassist:${property("javassist.version")}") + implementation("org.jboss.shrinkwrap:shrinkwrap-api:${property("shrinkwrap.version")}") + implementation("org.jboss.shrinkwrap:shrinkwrap-impl-base:${property("shrinkwrap.version")}") + implementation("net.lingala.zip4j:zip4j:${property("zip4j.version")}") + + /* This dependency needs to be explicitly added, because shrinkwrap-resolver-api-maven-embedded + and shrinkwrap-resolver-impl-maven-embedded depend on different versions of it. + This would lead to issues when the HiveMQ Testcontainer is included in maven projects. */ + implementation("org.codehaus.plexus:plexus-utils:3.2.1") + implementation("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-api-maven-embedded:${property("shrinkwrap-resolver.version")}") { + exclude("org.codehouse.plexus", "plexus-utils") + } + runtimeOnly("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-impl-maven-embedded:${property("shrinkwrap-resolver.version")}") { + exclude("org.codehouse.plexus", "plexus-utils") + } + + compileOnly("com.hivemq:hivemq-extension-sdk:${property("hivemq-extension-sdk.version")}") + + testImplementation("org.junit.jupiter:junit-jupiter-api:${property("junit5.version")}") + testImplementation("com.hivemq:hivemq-extension-sdk:${property("hivemq-extension-sdk.version")}") + testImplementation("com.hivemq:hivemq-mqtt-client:${property("hivemq-mqtt-client.version")}") + testImplementation("org.apache.httpcomponents:httpclient:${property("httpclient.version")}") + testImplementation("ch.qos.logback:logback-classic:${property("logback.version")}") + +} + +tasks.withType { + useJUnitPlatform() +} diff --git a/modules/hivemq/gradle.properties b/modules/hivemq/gradle.properties new file mode 100644 index 00000000000..0dbcbbf3223 --- /dev/null +++ b/modules/hivemq/gradle.properties @@ -0,0 +1,26 @@ +version=2.0.0 +# +# main dependencies +# +testcontainers.version=1.16.0 +hivemq-extension-sdk.version=4.4.4 +junit4.version=4.13.2 +annotations.version=22.0.0 +commons-lang.version=3.12.0 +commons-io.version=2.11.0 +guava.version=30.1.1-jre +javassist.version=3.28.0-GA +shrinkwrap.version=1.2.6 +shrinkwrap-resolver.version=3.1.4 +zip4j.version=2.9.0 +# +# test dependencies +# +hivemq-mqtt-client.version=1.2.2 +httpclient.version=4.5.13 +logback.version=1.2.3 +junit5.version=5.8.1 +# +# plugins +# +plugin.nexus-publish.version=1.1.0 diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java new file mode 100644 index 00000000000..458ab02dd9d --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java @@ -0,0 +1,179 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import net.lingala.zip4j.ZipFile; +import org.apache.commons.lang3.SystemUtils; +import org.jetbrains.annotations.NotNull; +import org.testcontainers.utility.MountableFile; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.AbstractMap; +import java.util.Map; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * This class automates the process of packaging a HiveMQ extension from a gradle project. + * It uses ./gradlew on MacOS and Linux and uses gradlew.bat on Windows to execute the gradle task. + * + * @author Yannick Weber + */ +public class GradleHiveMQExtensionSupplier implements Supplier { + + private static final @NotNull Pattern ROOT_PROJECT_PATTERN = Pattern.compile(".*'(.*)'"); + private static final @NotNull String PROPERTY_REGEX = "(.*): (.*)"; + + private static final @NotNull String BUILD_STARTED = + "=================================================================\n" + + "=== Embedded Gradle build started: %s ===\n" + + "=================================================================\n"; + + private static final @NotNull String BUILD_STOPPED = + "=================================================================\n" + + "=== Embedded Gradle build stopped: %s ===\n" + + "================================================================="; + + private static final @NotNull String TASK = "hivemqExtensionZip"; + + private final @NotNull File gradleProjectDirectory; + private boolean quiet = false; + + /** + * Creates a Gradle HiveMQ extension {@link Supplier}. + * It uses the gradle wrapper of the gradle project associated with the given It uses the build.gradle file. + * + * @param gradleProjectDirectory the gradle project directory of the HiveMQ extension to supply. + */ + public GradleHiveMQExtensionSupplier(final @NotNull File gradleProjectDirectory) { + + if (!gradleProjectDirectory.exists()) { + throw new IllegalStateException(gradleProjectDirectory + " does not exist."); + } + if (!gradleProjectDirectory.canRead()) { + throw new IllegalStateException(gradleProjectDirectory + " is not readable."); + } + this.gradleProjectDirectory = gradleProjectDirectory; + } + + /** + * Packages the HiveMQ extension, copies it to a temporary directory and returns the directory as a {@link MountableFile}. + * + * @return the {@link MountableFile} of the packaged HiveMQ extension + */ + @Override + public @NotNull MountableFile get() { + System.out.printf((BUILD_STARTED) + "%n", gradleProjectDirectory); + + try { + final ProcessBuilder extensionZipProcessBuilder = new ProcessBuilder(); + extensionZipProcessBuilder.directory(gradleProjectDirectory); + extensionZipProcessBuilder.command(getCommandForOs(gradleProjectDirectory), TASK); + extensionZipProcessBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); + + if (!quiet) { + extensionZipProcessBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT); + } + final Process extensionZipProcess = extensionZipProcessBuilder.start(); + final int extensionZipExitCode = extensionZipProcess.waitFor(); + if (extensionZipExitCode != 0) { + throw new IllegalStateException("Gradle build exited with code " + extensionZipExitCode); + } + + final ProcessBuilder propertiesProcessBuilder = new ProcessBuilder(); + propertiesProcessBuilder.directory(gradleProjectDirectory); + propertiesProcessBuilder.command(getCommandForOs(gradleProjectDirectory), "properties", "-q"); + propertiesProcessBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); + + final Process propertiesProcess = propertiesProcessBuilder.start(); + final int propertiesExitCode = propertiesProcess.waitFor(); + if (propertiesExitCode != 0) { + throw new IllegalStateException("Gradle build exited with code " + propertiesExitCode); + } + + final BufferedReader br = new BufferedReader(new InputStreamReader(propertiesProcess.getInputStream())); + + final Map gradleProperties = br.lines() + .filter(s -> s.matches(PROPERTY_REGEX)) + .map(s -> { + final String[] splits = s.split(": "); + return new AbstractMap.SimpleEntry<>(splits[0], splits[1]); + }) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + + System.out.printf((BUILD_STOPPED) + "%n", this.gradleProjectDirectory); + + final String projectVersion = gradleProperties.get("version"); + final String rootProject = gradleProperties.get("rootProject"); + final Matcher matcher = ROOT_PROJECT_PATTERN.matcher(rootProject); + final boolean b = matcher.find(); + final String projectName = matcher.group(1); + + final ZipFile zipFile = new ZipFile( + new File(gradleProjectDirectory, + "build/hivemq-extension/" + projectName + "-" + projectVersion + ".zip")); + final Path tempDirectory = Files.createTempDirectory(""); + + zipFile.extractAll(tempDirectory.toString()); + return MountableFile.forHostPath(tempDirectory.resolve(projectName)); + + } catch (final Exception e) { + throw new RuntimeException("Exception while building the HiveMQ extension with gradle.", e); + } + } + + private @NotNull String getCommandForOs(final @NotNull File gradleProjectFile) { + if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_LINUX) { + final String gradleWrapper = gradleProjectFile + "/gradlew"; + final File gradleWrapperBashFile = new File(gradleWrapper); + if (gradleWrapperBashFile.exists()) { + if (!gradleWrapperBashFile.canExecute()) { + throw new IllegalStateException("Gradle Wrapper " + gradleWrapperBashFile.getAbsolutePath() + " can not be executed."); + } + return gradleWrapperBashFile.getAbsolutePath(); + } + } else if (SystemUtils.IS_OS_WINDOWS) { + final String gradleWrapperBat = gradleProjectFile + "/gradlew.bat"; + final File gradleWrapperBatFile = new File(gradleWrapperBat); + if (gradleWrapperBatFile.exists()) { + if (!gradleWrapperBatFile.canExecute()) { + throw new IllegalStateException("Gradle Wrapper " + gradleWrapperBatFile.getAbsolutePath() + " can not be executed."); + } + return gradleWrapperBatFile.getAbsolutePath(); + } + } + throw new IllegalStateException("Unknown OS Version"); + + } + + /** + * Suppress stdout of the gradle build. + * + * @return self + */ + @NotNull + public GradleHiveMQExtensionSupplier quiet() { + this.quiet = true; + return this; + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java new file mode 100644 index 00000000000..c09ecf58b4d --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -0,0 +1,665 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import javassist.ClassPool; +import javassist.NotFoundException; +import org.apache.commons.io.FileUtils; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.exporter.ZipExporter; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.images.builder.ImageFromDockerfile; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.time.Duration; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Yannick Weber + */ +@SuppressWarnings("UnusedReturnValue") +public class HiveMQContainer extends GenericContainer { + + private final static @NotNull Logger logger = LoggerFactory.getLogger(HiveMQContainer.class); + + private static final @NotNull String validPluginXML = + "" + // + " %s" + // + " %s" + // + " %s" + // + " %s" + // + " %s" + // + ""; + + private static final @NotNull DockerImageName DEFAULT_HIVEMQ_CE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq-ce"); + private static final @NotNull DockerImageName DEFAULT_HIVEMQ_EE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq4"); + private static final @NotNull String DEFAULT_HIVEMQ_CE_TAG = "2021.3"; + + public static final int DEBUGGING_PORT = 9000; + public static final int MQTT_PORT = 1883; + public static final int CONTROL_CENTER_PORT = 8080; + @SuppressWarnings("OctalInteger") + private static final int MODE = 0777; + private static final @NotNull Pattern EXTENSION_ID_PATTERN = Pattern.compile("(.+?)"); + + private final @NotNull ConcurrentHashMap containerOutputLatches = new ConcurrentHashMap<>(); + private volatile boolean silent = false; + private volatile boolean controlCenterEnabled = false; + + private final @NotNull MultiLogMessageWaitStrategy waitStrategy = new MultiLogMessageWaitStrategy(); + + public HiveMQContainer() { + this(DEFAULT_HIVEMQ_CE_IMAGE_NAME.withTag(DEFAULT_HIVEMQ_CE_TAG)); + } + + public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { + super(dockerImageName); + + dockerImageName.assertCompatibleWith(DEFAULT_HIVEMQ_CE_IMAGE_NAME, DEFAULT_HIVEMQ_EE_IMAGE_NAME); + + addExposedPort(MQTT_PORT); + + waitStrategy.withRegEx("(.*)Started HiveMQ in(.*)"); + waitingFor(waitStrategy); + + withLogConsumer(outputFrame -> { + final String utf8String = outputFrame.getUtf8String(); + if (utf8String.startsWith("Listening for transport dt_socket at address:")) { + System.out.println("Listening for transport dt_socket at address: " + getMappedPort(DEBUGGING_PORT)); + } else if (!silent) { + System.out.print(utf8String); + } + }); + withLogConsumer((outputFrame) -> { + if (!containerOutputLatches.isEmpty()) { + containerOutputLatches.forEach((regEx, latch) -> { + if (outputFrame.getUtf8String().matches("(?s)" + regEx)) { + logger.debug("Container Output '{}' matched RegEx '{}'", outputFrame.getUtf8String(), regEx); + latch.countDown(); + } else { + logger.debug("Container Output '{}' did not match RegEx '{}'", outputFrame.getUtf8String(), regEx); + } + }); + } + }); + } + + @Override + public void start() { + super.start(); + if (controlCenterEnabled) { + logger.info("The HiveMQ Control Center is reachable under: http://localhost:{}", getMappedPort(CONTROL_CENTER_PORT)); + } + } + + /** + * Adds a wait condition for the extension with this name. + *

+ * Must be called before the container is started. + * + * @param extensionName the extension to wait for + * @return self + */ + public @NotNull HiveMQContainer waitForExtension(final @NotNull String extensionName) { + final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) started successfully(.*)"; + waitStrategy.withRegEx(regEX); + return self(); + } + + /** + * Adds a wait condition for this {@link HiveMQExtension} + *

+ * Must be called before the container is started. + * + * @param extension the extension to wait for + * @return self + */ + public @NotNull HiveMQContainer waitForExtension(final @NotNull HiveMQExtension extension) { + return this.waitForExtension(extension.getName()); + } + + /** + * Enables the possibility for remote debugging clients to connect. + *

+ * Must be called before the container is started. + * + * @return self + */ + public @NotNull HiveMQContainer withDebugging() { + addExposedPorts(DEBUGGING_PORT); + withEnv("JAVA_OPTS", "-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:" + DEBUGGING_PORT + ",server=y,suspend=y"); + return self(); + } + + /** + * Sets the logging {@link Level} inside the container. + *

+ * Must be called before the container is started. + * + * @param level the {@link Level} + * @return self + */ + public @NotNull HiveMQContainer withLogLevel(final @NotNull Level level) { + this.withEnv("HIVEMQ_LOG_LEVEL", level.name()); + return self(); + } + + /** + * Wraps the given class and all its subclasses into an extension + * and puts it into '/opt/hivemq/extensions/{extension-id}' inside the container. + *

+ * Must be called before the container is started. + * + * @param hiveMQExtension the {@link HiveMQExtension} of the extension + * @return self + */ + public @NotNull HiveMQContainer withExtension(final @NotNull HiveMQExtension hiveMQExtension) { + try { + final File extension = createExtension(hiveMQExtension); + final MountableFile mountableExtension = MountableFile.forHostPath(extension.getPath(), MODE); + withCopyFileToContainer(mountableExtension, "/opt/hivemq/extensions/" + hiveMQExtension.getId()); + } catch (final Exception e) { + throw new ContainerLaunchException(e.getMessage() == null ? "" : e.getMessage(), e); + } + return self(); + } + + /** + * Puts the given extension folder into '/opt/hivemq/extensions/{directory-name}' inside the container. + * It must at least contain a valid hivemq-extension.xml and a valid extension.jar in order to be executed. + * The directory-name is taken from the id defined in the hivemq-extension.xml. + *

+ * Must be called before the container is started. + * + * @param mountableExtension the extension folder on the host machine + * @return self + */ + public @NotNull HiveMQContainer withExtension(final @NotNull MountableFile mountableExtension) { + final File extensionDir = new File(mountableExtension.getResolvedPath()); + if (!extensionDir.exists()) { + throw new ContainerLaunchException("Extension '" + mountableExtension.getFilesystemPath() + "' could not be mounted. It does not exist."); + } + if (!extensionDir.isDirectory()) { + throw new ContainerLaunchException("Extension '" + mountableExtension.getFilesystemPath() + "' could not be mounted. It is not a directory."); + } + try { + final String extensionDirName = getExtensionDirectoryName(extensionDir); + final String containerPath = "/opt/hivemq/extensions/" + extensionDirName; + withCopyFileToContainer(cloneWithFileMode(mountableExtension, MODE), containerPath); + logger.info("Putting extension '{}' into '{}'", extensionDirName, containerPath); + } catch (final Exception e) { + throw new ContainerLaunchException(e.getMessage() == null ? "" : e.getMessage(), e); + } + return self(); + } + + private @NotNull String getExtensionDirectoryName(final @NotNull File extensionDirectory) throws IOException { + final File file = new File(extensionDirectory, "hivemq-extension.xml"); + final String xml = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + final Matcher matcher = EXTENSION_ID_PATTERN.matcher(xml); + + if (!matcher.find()) { + throw new IllegalStateException("Could not parse extension id from '" + file.getAbsolutePath() + "'"); + } + return matcher.group(1); + } + + private @NotNull File createExtension(final @NotNull HiveMQExtension hiveMQExtension) + throws Exception { + + final File tempDir = Files.createTempDirectory("").toFile(); + + final File extensionDir = new File(tempDir, hiveMQExtension.getId()); + FileUtils.writeStringToFile(new File(extensionDir, "hivemq-extension.xml"), + String.format( + validPluginXML, + hiveMQExtension.getId(), + hiveMQExtension.getName(), + hiveMQExtension.getVersion(), + hiveMQExtension.getPriority(), + hiveMQExtension.getStartPriority()), + Charset.defaultCharset()); + + if (hiveMQExtension.isDisabledOnStartup()) { + final File disabled = new File(extensionDir, "DISABLED"); + final boolean newFile = disabled.createNewFile(); + if (!newFile) { + throw new ContainerLaunchException("Could not create DISABLED file '" + disabled.getAbsolutePath() + "' on host machine."); + } + } + + final JavaArchive javaArchive = + ShrinkWrap.create(JavaArchive.class) + .addAsServiceProviderAndClasses(ExtensionMain.class, hiveMQExtension.getMainClass()); + + putSubclassesIntoJar(hiveMQExtension.getId(), hiveMQExtension.getMainClass(), javaArchive); + for (final Class additionalClass : hiveMQExtension.getAdditionalClasses()) { + javaArchive.addClass(additionalClass); + putSubclassesIntoJar(hiveMQExtension.getId(), additionalClass, javaArchive); + } + + javaArchive.as(ZipExporter.class).exportTo(new File(extensionDir, "extension.jar")); + + return extensionDir; + } + + private void putSubclassesIntoJar( + final @NotNull String extensionId, + final @Nullable Class clazz, + final @NotNull JavaArchive javaArchive) throws NotFoundException { + + if (clazz != null) { + final Set subClassNames = + ClassPool.getDefault().get(clazz.getName()).getClassFile().getConstPool().getClassNames(); + for (final String subClassName : subClassNames) { + final String className = subClassName.replaceAll("/", "."); + + if (!className.startsWith("[L")) { + logger.debug("Trying to package subclass '{}' into extension '{}'.", className, extensionId); + javaArchive.addClass(className); + } else { + logger.debug("Class '{}' will be ignored.", className); + } + } + } + } + + /** + * Removes the specified prepackaged extension folders from '/opt/hivemq/extensions' before the container is built. + * Note: this creates a custom docker image. + *

+ * Must be called before the container is started. + * + * @param extensionIds the prepackaged extensions to remove + * @return self + */ + public @NotNull HiveMQContainer withoutPrepackagedExtensions(final @NotNull String... extensionIds) { + final String dockerImageName = getDockerImageName(); + setImage(new ImageFromDockerfile(dockerImageName + "-custom") + .withDockerfileFromBuilder(builder -> { + builder.from(dockerImageName); + for (final String extensionId : extensionIds) { + builder.run("rm", "-rf", "/opt/hivemq/extensions/" + extensionId); + } + })); + return self(); + } + + /** + * Removes all prepackaged extension folders from '/opt/hivemq/extensions' before the container is built. + * Note: this creates a custom docker image. + *

+ * Must be called before the container is started. + * + * @return self + */ + public @NotNull HiveMQContainer withoutPrepackagedExtensions() { + final String dockerImageName = getDockerImageName(); + setImage(new ImageFromDockerfile(dockerImageName + "-custom") + .withDockerfileFromBuilder(builder -> + builder.from(dockerImageName) + .run("rm", "-rf", "/opt/hivemq/extensions/"))); + return self(); + } + + /** + * Puts the given license into '/opt/hivemq/license/' inside the container. + * It must end with '.lic' or '.elic'. + *

+ * Must be called before the container is started. + * + * @param mountableLicense the license file on the host machine + * @return self + */ + public @NotNull HiveMQContainer withLicense(final @NotNull MountableFile mountableLicense) { + final File licenseFile = new File(mountableLicense.getResolvedPath()); + if (!licenseFile.exists()) { + throw new ContainerLaunchException("License file '" + mountableLicense.getFilesystemPath() + "' does not exist."); + } + if (!licenseFile.getName().endsWith(".lic") && !licenseFile.getName().endsWith(".elic")) { + throw new ContainerLaunchException("License file '" + mountableLicense.getFilesystemPath() + "' does not end wit '.lic' or '.elic'."); + } + final String containerPath = "/opt/hivemq/license/" + licenseFile.getName(); + withCopyFileToContainer(cloneWithFileMode(mountableLicense, MODE), containerPath); + logger.info("Putting license '{}' into '{}'.", licenseFile.getAbsolutePath(), containerPath); + return self(); + } + + /** + * Overwrites the HiveMQ configuration in '/opt/hivemq/conf/' inside the container. + *

+ * Must be called before the container is started. + * + * @param mountableConfig the config file on the host machine + * @return self + */ + public @NotNull HiveMQContainer withHiveMQConfig(final @NotNull MountableFile mountableConfig) { + final File config = new File(mountableConfig.getResolvedPath()); + if (!config.exists()) { + throw new ContainerLaunchException("HiveMQ config file '" + mountableConfig.getFilesystemPath() + "' does not exist."); + } + final String containerPath = "/opt/hivemq/conf/config.xml"; + withCopyFileToContainer(cloneWithFileMode(mountableConfig, MODE), containerPath); + logger.info("Putting '{}' into '{}'.", config.getAbsolutePath(), containerPath); + return self(); + } + + /** + * Puts the given file into the root of the extension's home '/opt/hivemq/extensions/{extensionId}/'. + * Note: the extension must be loaded before the file is put. + *

+ * Must be called before the container is started. + * + * @param file the file on the host machine + * @param extensionId the extension + * @return self + */ + public @NotNull HiveMQContainer withFileInExtensionHomeFolder( + final @NotNull MountableFile file, + final @NotNull String extensionId) { + + return withFileInExtensionHomeFolder(file, extensionId, ""); + } + + /** + * Puts the given file into given subdirectory of the extensions's home '/opt/hivemq/extensions/{id}/{pathInExtensionHome}/' + * Note: the extension must be loaded before the file is put. + *

+ * Must be called before the container is started. + * + * @param file the file on the host machine + * @param extensionId the extension + * @param pathInExtensionHome the path + * @return self + */ + public @NotNull HiveMQContainer withFileInExtensionHomeFolder( + final @NotNull MountableFile file, + final @NotNull String extensionId, + final @NotNull String pathInExtensionHome) { + + return withFileInHomeFolder(file, "/extensions/" + extensionId + PathUtil.prepareAppendPath(pathInExtensionHome)); + } + + /** + * Puts the given file into the given subdirectory of the HiveMQ home folder '/opt/hivemq/{pathInHomeFolder}'. + *

+ * Must be called before the container is started. + * + * @param mountableFile the file on the host machine + * @param pathInHomeFolder the path + * @return self + */ + public @NotNull HiveMQContainer withFileInHomeFolder( + final @NotNull MountableFile mountableFile, + final @NotNull String pathInHomeFolder) { + + final File file = new File(mountableFile.getResolvedPath()); + + if (pathInHomeFolder.trim().isEmpty()) { + throw new ContainerLaunchException("pathInHomeFolder must not be empty"); + } + + if (!file.exists()) { + throw new ContainerLaunchException("File '" + mountableFile.getFilesystemPath() + "‘ does not exist."); + } + final String containerPath = "/opt/hivemq" + PathUtil.prepareAppendPath(pathInHomeFolder); + withCopyFileToContainer(cloneWithFileMode(mountableFile, MODE), containerPath); + logger.info("Putting file '{}' into container path '{}'.", file.getAbsolutePath(), containerPath); + return self(); + } + + /** + * Disables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after {timeOut}. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @param timeout the timeout + * @throws TimeoutException if the extension was not disabled within the configured timeout + */ + public void disableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory, + final @NotNull Duration timeout) throws TimeoutException { + + final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) stopped successfully(.*)"; + try { + final String containerPath = "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; + + final CountDownLatch latch = new CountDownLatch(1); + containerOutputLatches.put(regEX, latch); + + execInContainer("touch", containerPath); + logger.info("Putting DISABLED file into container path '{}'", containerPath); + + final boolean await = latch.await(timeout.getSeconds(), TimeUnit.SECONDS); + if (!await) { + throw new TimeoutException("Extension disabling timed out after '" + timeout.getSeconds() + "' seconds. " + + "Maybe you are using a HiveMQ Community Edition image, " + + "which does not support disabling of extensions"); + } + } catch (final InterruptedException | IOException e) { + throw new RuntimeException(e); + } finally { + containerOutputLatches.remove(regEX); + } + } + + /** + * Disables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after 60 seconds. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @throws TimeoutException if the extension was not disabled within 60 seconds + */ + public void disableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory) throws TimeoutException { + disableExtension(extensionName, extensionDirectory, Duration.ofSeconds(60)); + } + + /** + * Disables the extension. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after {timeOut}. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @param timeout the timeout + * @throws TimeoutException if the extension was not disabled within the configured timeout + */ + public void disableExtension( + final @NotNull HiveMQExtension hiveMQExtension, + final @NotNull Duration timeout) throws TimeoutException { + disableExtension(hiveMQExtension.getName(), hiveMQExtension.getId(), timeout); + } + + /** + * Disables the extension. + * This method blocks until the HiveMQ log for successful disabling is consumed or it times out after 60 seconds. + * Note: Disabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @throws TimeoutException if the extension was not disabled within 60 seconds + */ + public void disableExtension(final @NotNull HiveMQExtension hiveMQExtension) throws TimeoutException { + disableExtension(hiveMQExtension, Duration.ofSeconds(60)); + } + + /** + * Enables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after {timeOut}. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @param timeout the timeout + * @throws TimeoutException if the extension was not enabled within the configured timeout + */ + public void enableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory, + final @NotNull Duration timeout) throws TimeoutException { + + final String regEX = "(.*)Extension \"" + extensionName + "\" version (.*) started successfully(.*)"; + try { + final String containerPath = "/opt/hivemq/extensions" + PathUtil.prepareInnerPath(extensionDirectory) + "DISABLED"; + + final CountDownLatch latch = new CountDownLatch(1); + containerOutputLatches.put(regEX, latch); + + execInContainer("rm", "-rf", containerPath); + logger.info("Removing DISABLED file in container path '{}'", containerPath); + + final boolean await = latch.await(timeout.getSeconds(), TimeUnit.SECONDS); + if (!await) { + throw new TimeoutException("Extension enabling timed out after '" + timeout.getSeconds() + "' seconds. " + + "Maybe you are using a HiveMQ Community Edition image, " + + "which does not support disabling of extensions"); + } + } catch (final InterruptedException | IOException e) { + throw new RuntimeException(e); + } finally { + containerOutputLatches.remove(regEX); + } + } + + /** + * Enables the extension with the given name and extension directory name. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after 60 seconds. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param extensionName the name of the extension to disable + * @param extensionDirectory the name of the extension's directory + * @throws TimeoutException if the extension was not enabled within 60 seconds + */ + public void enableExtension( + final @NotNull String extensionName, + final @NotNull String extensionDirectory) throws TimeoutException { + enableExtension(extensionName, extensionDirectory, Duration.ofSeconds(60)); + } + + /** + * Enables the extension. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after {timeOut}. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @param timeout the timeout + * @throws TimeoutException if the extension was not enabled within the configured timeout + */ + public void enableExtension( + final @NotNull HiveMQExtension hiveMQExtension, + final @NotNull Duration timeout) throws TimeoutException { + enableExtension(hiveMQExtension.getName(), hiveMQExtension.getId(), timeout); + } + + /** + * Enables the extension. + * This method blocks until the HiveMQ log for successful enabling is consumed or it times out after {timeOut}. + * Note: Enabling Extensions is a HiveMQ Enterprise feature, it will not work when using the HiveMQ Community Edition. + *

+ * This can only be called once the container is started. + * + * @param hiveMQExtension the extension + * @throws TimeoutException if the extension was not enabled within 60 seconds + */ + public void enableExtension(final @NotNull HiveMQExtension hiveMQExtension) throws TimeoutException { + enableExtension(hiveMQExtension, Duration.ofSeconds(60)); + } + + /** + * Determines whether the stdout of the container is printed to System.out. + * + * @param silent whether the container is silent. + * @return self + */ + public @NotNull HiveMQContainer silent(final boolean silent) { + this.silent = silent; + return self(); + } + + /** + * Enables connection to the HiveMQ Control Center on host port 8080. + * Note: the control center is a HiveMQ 4 Enterprise feature. + *

+ * Must be called before the container is started. + * + * @return self + */ + public @NotNull HiveMQContainer withControlCenter() { + addExposedPorts(CONTROL_CENTER_PORT); + controlCenterEnabled = true; + return self(); + } + + /** + * Get the mapped port for the MQTT port of the container. + *

+ * Must be called after the container is started. + * + * @return the port on the host machine for mqtt clients to connect + */ + public int getMqttPort() { + return this.getMappedPort(MQTT_PORT); + } + + @Override + public void stop() { + waitStrategy.reset(); + super.stop(); + } + + private @NotNull MountableFile cloneWithFileMode(final @NotNull MountableFile mountableFile, final int mode) { + return MountableFile.forHostPath(mountableFile.getResolvedPath(), mode); + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java new file mode 100644 index 00000000000..954cbf35cf9 --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -0,0 +1,168 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.google.common.collect.ImmutableList; +import com.hivemq.extension.sdk.api.ExtensionMain; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Yannick Weber + */ +public class HiveMQExtension { + + private final @NotNull String id; + private final @NotNull String name; + private final @NotNull String version; + private final int priority; + private final int startPriority; + private final boolean disabledOnStartup; + private final @NotNull Class mainClass; + private final @NotNull ImmutableList> additionalClasses; + + private HiveMQExtension( + final @NotNull String id, + final @NotNull String name, + final @NotNull String version, + final int priority, + final int startPriority, + final boolean disabledOnStartup, + final @NotNull Class mainClass, + final @NotNull ImmutableList> additionalClasses) { + + this.id = id; + this.name = name; + this.version = version; + this.priority = priority; + this.startPriority = startPriority; + this.disabledOnStartup = disabledOnStartup; + this.mainClass = mainClass; + this.additionalClasses = additionalClasses; + } + + public @NotNull String getId() { + return id; + } + + public @NotNull String getName() { + return name; + } + + public @NotNull String getVersion() { + return version; + } + + public int getPriority() { + return priority; + } + + public int getStartPriority() { + return startPriority; + } + + public boolean isDisabledOnStartup() { + return disabledOnStartup; + } + + public @NotNull Class getMainClass() { + return mainClass; + } + + public @NotNull ImmutableList> getAdditionalClasses() { + return additionalClasses; + } + + public static @NotNull Builder builder() { + return new Builder(); + } + + public static final class Builder { + private @Nullable String id; + private @Nullable String name; + private @Nullable String version; + private int priority = 0; + private int startPriority = 0; + private boolean disabledOnStartup = false; + private @Nullable Class mainClass; + private final @NotNull ImmutableList.Builder> additionalClassesBuilder = ImmutableList.builder(); + + public HiveMQExtension build() { + if (id == null || id.isEmpty()) { + throw new IllegalArgumentException("extension id must not be null or empty"); + } + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("extension name must not be null or empty"); + } + if (version == null || version.isEmpty()) { + throw new IllegalArgumentException("extension version must not be null or empty"); + } + if (mainClass == null) { + throw new IllegalArgumentException("extension main class must not be null"); + } + return new HiveMQExtension( + id, + name, + version, + priority, + startPriority, + disabledOnStartup, + mainClass, + additionalClassesBuilder.build() + ); + } + + public @NotNull Builder id(final @NotNull String id) { + this.id = id; + return this; + } + + public @NotNull Builder name(final @NotNull String name) { + this.name = name; + return this; + } + + public @NotNull Builder version(final @NotNull String version) { + this.version = version; + return this; + } + + public @NotNull Builder priority(final int priority) { + this.priority = priority; + return this; + } + + public @NotNull Builder startPriority(final int startPriority) { + this.startPriority = startPriority; + return this; + } + + public @NotNull Builder disabledOnStartup(final boolean disabledOnStartup) { + this.disabledOnStartup = disabledOnStartup; + return this; + } + + public @NotNull Builder mainClass(final @NotNull Class mainClass) { + this.mainClass = mainClass; + return this; + } + + public @NotNull Builder addAdditionalClass(final @NotNull Class clazz) { + this.additionalClassesBuilder.add(clazz); + return this; + } + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java new file mode 100644 index 00000000000..d4f8e5d5582 --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java @@ -0,0 +1,111 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import net.lingala.zip4j.ZipFile; +import org.jboss.shrinkwrap.resolver.api.maven.embedded.BuiltProject; +import org.jboss.shrinkwrap.resolver.api.maven.embedded.EmbeddedMaven; +import org.jboss.shrinkwrap.resolver.api.maven.embedded.pom.equipped.PomEquippedEmbeddedMaven; +import org.jetbrains.annotations.NotNull; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Properties; +import java.util.function.Supplier; + +/** + * This class automates the process of packaging a HiveMQ extension from a maven project. + * + * @author Yannick Weber + */ +public class MavenHiveMQExtensionSupplier implements Supplier { + + private final @NotNull String pomFile; + private boolean quiet = false; + private final @NotNull Properties properties = new Properties(); + + /** + * This {@link Supplier} can be used if the current maven project is the HiveMQ Extension to supply. + * It uses the pom.xml file of the current maven project. + * + * @return a {@link MavenHiveMQExtensionSupplier} for the current maven project + */ + public static @NotNull MavenHiveMQExtensionSupplier direct() { + return new MavenHiveMQExtensionSupplier("pom.xml"); + } + + /** + * Creates a Maven HiveMQ extension {@link Supplier}. + * + * @param pomFile the path of the pom.xml of the HiveMQ extension to supply. + */ + public MavenHiveMQExtensionSupplier(final @NotNull String pomFile) { + this.pomFile = pomFile; + } + + /** + * Packages the HiveMQ extension, copies it to a temporary directory and returns the directory as a {@link MountableFile}. + * + * @return the {@link MountableFile} of the packaged HiveMQ extension + */ + @Override + public @NotNull MountableFile get() { + final PomEquippedEmbeddedMaven embeddedMaven = EmbeddedMaven.forProject(pomFile); + embeddedMaven + .setGoals("package") + .setQuiet(quiet) + .setBatchMode(true); + embeddedMaven.setProperties(properties); + final BuiltProject aPackage = embeddedMaven.build(); + final File targetDirectory = aPackage.getTargetDirectory(); + final String version = aPackage.getModel().getVersion(); + final String artifactId = aPackage.getModel().getArtifactId(); + + final ZipFile zipFile = new ZipFile(new File(targetDirectory, artifactId + "-" + version + "-distribution.zip")); + + try { + final Path tempDirectory = Files.createTempDirectory(""); + zipFile.extractAll(tempDirectory.toString()); + return MountableFile.forHostPath(tempDirectory.resolve(artifactId)); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Suppress stdout of the maven build. + * + * @return self + */ + public @NotNull MavenHiveMQExtensionSupplier quiet() { + this.quiet = true; + return this; + } + + /** + * Add a custom property for the maven packaging. + * + * @param key the name of the property + * @param value the value of the property + * @return self + */ + public @NotNull MavenHiveMQExtensionSupplier addProperty(final @NotNull String key, final @NotNull String value) { + properties.put(key, value); + return this; + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java new file mode 100644 index 00000000000..82bf87df9c6 --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java @@ -0,0 +1,78 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.jetbrains.annotations.NotNull; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.WaitingConsumer; +import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; +import org.testcontainers.utility.LogUtils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; + +/** + * This is a wait strategy to wait for multiple log patterns. + * The wait strategy will continue when every log pattern is matched at least once. + * + * @author Yannick Weber + */ +class MultiLogMessageWaitStrategy extends AbstractWaitStrategy { + + private final @NotNull ConcurrentHashMap regexes = new ConcurrentHashMap<>(); + + @Override + protected void waitUntilReady() { + WaitingConsumer waitingConsumer = new WaitingConsumer(); + LogUtils.followOutput(DockerClientFactory.instance().client(), waitStrategyTarget.getContainerId(), waitingConsumer); + + Predicate waitPredicate = outputFrame -> { + if (regexes.isEmpty()) { + return true; + } + regexes.entrySet().forEach(stringBooleanEntry -> { + final boolean matched = outputFrame.getUtf8String().matches("(?s)" + stringBooleanEntry.getKey()); + if (matched) { + stringBooleanEntry.setValue(true); + } + }); + return regexes.values().stream().reduce(Boolean::logicalAnd).orElse(true); + }; + + try { + waitingConsumer.waitUntil(waitPredicate, startupTimeout.getSeconds(), TimeUnit.SECONDS, 1); + } catch (TimeoutException e) { + throw new ContainerLaunchException("Timed out waiting for log output matching '" + regexes + "'"); + } + } + + public @NotNull MultiLogMessageWaitStrategy withRegEx(final @NotNull String regEx) { + regexes.put(regEx, false); + return this; + } + + public @NotNull MultiLogMessageWaitStrategy reset() { + for (final Map.Entry stringBooleanEntry : regexes.entrySet()) { + stringBooleanEntry.setValue(false); + } + return this; + } +} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java new file mode 100755 index 00000000000..bca4609e0e9 --- /dev/null +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Yannick Weber + */ +class PathUtil { + + static @NotNull String prepareInnerPath(@NotNull String innerPath) { + if ("/".equals(innerPath) || innerPath.isEmpty()) { + return "/"; + } + if (!innerPath.startsWith("/")) { + innerPath = "/" + innerPath; + } + if (!innerPath.endsWith("/")) { + innerPath += "/"; + } + return innerPath; + } + + static @NotNull String prepareAppendPath(@NotNull String appendPath) { + if (!appendPath.startsWith("/")) { + appendPath = "/" + appendPath; + } + return appendPath; + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java new file mode 100644 index 00000000000..92819a0b27f --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -0,0 +1,51 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.utility.DockerImageName; + +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithControlCenterIT { + + public static final int CONTROL_CENTER_PORT = 8080; + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void test() throws Exception { + + final HiveMQContainer extension = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + .withControlCenter(); + + extension.start(); + + final CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + final HttpUriRequest request = new HttpGet("http://localhost:" + extension.getMappedPort(CONTROL_CENTER_PORT)); + httpClient.execute(request); + + extension.stop(); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java new file mode 100755 index 00000000000..0d8495787b2 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -0,0 +1,61 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.client.mqtt.datatypes.MqttQos; +import com.hivemq.client.mqtt.exceptions.MqttSessionExpiredException; +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Yannick Weber + */ +public class ContainerWithCustomConfigIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQContainer extension = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + .withHiveMQConfig(MountableFile.forClasspathResource("/config.xml")); + + extension.start(); + + final Mqtt5BlockingClient publisher = Mqtt5Client.builder() + .identifier("publisher") + .serverPort(extension.getMqttPort()) + .buildBlocking(); + + publisher.connect(); + + assertThrows(MqttSessionExpiredException.class, () -> { + // this should fail since only QoS 0 is allowed by the configuration + publisher.publishWith() + .topic("test/topic") + .qos(MqttQos.EXACTLY_ONCE) + .send(); + }); + + extension.stop(); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java new file mode 100755 index 00000000000..421826fd1f7 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -0,0 +1,58 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithExtensionFromDirectoryIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQContainer extension = + new HiveMQContainer() + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension") + .withLogLevel(Level.DEBUG); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test_wrongDirectoryName() throws Exception { + final HiveMQContainer extension = + new HiveMQContainer() + .withExtension(MountableFile.forClasspathResource("/modifier-extension-wrong-name")) + .waitForExtension("Modifier Extension") + .withLogLevel(Level.DEBUG); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java new file mode 100755 index 00000000000..bc87e204947 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -0,0 +1,56 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.MyExtension; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; + +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithExtensionIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtension.class).build(); + + final HiveMQContainer extension = + new HiveMQContainer() + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java new file mode 100755 index 00000000000..a5dbb095cec --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -0,0 +1,50 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.MyExtensionWithSubclasses; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; + +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithExtensionSubclassIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtensionWithSubclasses.class).build(); + + final HiveMQContainer extension = + new HiveMQContainer() + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension) + .withLogLevel(Level.DEBUG); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java new file mode 100755 index 00000000000..eb8e7cd05a3 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -0,0 +1,93 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithFileInExtensionHomeIT { + + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCheckerExtension.class).build(); + + final HiveMQContainer extension = + new HiveMQContainer() + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInExtensionHomeFolder( + MountableFile.forClasspathResource("/additionalFile.txt"), + "extension-1", + "/additionalFiles/my-file.txt"); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + + public static class FileCheckerExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File extensionHomeFolder = extensionStartInput.getExtensionInformation().getExtensionHomeFolder(); + + final File additionalFile = new File(extensionHomeFolder, "additionalFiles/my-file.txt"); + + if (additionalFile.exists()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java new file mode 100755 index 00000000000..b2749c790c2 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -0,0 +1,90 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithFileInHomeIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCheckerExtension.class).build(); + + final HiveMQContainer extension = + new HiveMQContainer() + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInHomeFolder(MountableFile.forClasspathResource("/additionalFile.txt"), + "/additionalFiles/my-file.txt"); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + + public static class FileCheckerExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); + + final File additionalFile = new File(homeFolder, "additionalFiles/my-file.txt"); + + if (additionalFile.exists()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java new file mode 100644 index 00000000000..c399ceebfcf --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java @@ -0,0 +1,46 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithGradleExtensionIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void test() throws Exception { + final MountableFile gradleExtension = new GradleHiveMQExtensionSupplier( + new File(getClass().getResource("/gradle-extension").toURI())) + .get(); + + final HiveMQContainer container = new HiveMQContainer() + .waitForExtension("Gradle Extension") + .withExtension(gradleExtension); + + container.start(); + TestPublishModifiedUtil.testPublishModified(container.getMqttPort()); + container.stop(); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java new file mode 100755 index 00000000000..ad195f9dd7a --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -0,0 +1,93 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithLicenseIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(LicenceCheckerExtension.class).build(); + + final HiveMQContainer extension = + new HiveMQContainer() + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withLicense(MountableFile.forClasspathResource("/myLicense.lic")) + .withLicense(MountableFile.forClasspathResource("/myExtensionLicense.elic")); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + + @SuppressWarnings("CodeBlock2Expr") + public static class LicenceCheckerExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); + final File myLicence = new File(homeFolder, "license/myLicense.lic"); + final File myExtensionLicence = new File(homeFolder, "license/myExtensionLicense.elic"); + + if (myLicence.exists() && myExtensionLicence.exists()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java new file mode 100644 index 00000000000..499196a3c7e --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java @@ -0,0 +1,49 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class ContainerWithMavenExtensionIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final MountableFile mavenExtension = new MavenHiveMQExtensionSupplier( + getClass().getResource("/maven-extension/pom.xml").getPath()) + .addProperty("HIVEMQ_GROUP_ID", "com.hivemq") + .addProperty("HIVEMQ_EXTENSION_SDK", "hivemq-extension-sdk") + .addProperty("HIVEMQ_EXTENSION_SDK_VERSION", "4.3.0") + .get(); + + final HiveMQContainer extension = new HiveMQContainer() + .waitForExtension("Maven Extension") + .withExtension(mavenExtension); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java new file mode 100644 index 00000000000..ed024ff9079 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -0,0 +1,153 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.client.mqtt.MqttClient; +import com.hivemq.client.mqtt.MqttGlobalPublishFilter; +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish; +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.auth.SimpleAuthenticator; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.builder.Builders; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.utility.DockerImageName; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Yannick Weber + */ +public class ContainerWithoutPlatformExtensionsIT { + + private final @NotNull HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .name("MyExtension") + .id("my-extension") + .version("1.0.0") + .mainClass(CheckerExtension.class).build(); + + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void removeAllPlatformExtensions() throws InterruptedException { + + final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withoutPrepackagedExtensions(); + + container.start(); + + final Mqtt5BlockingClient client = MqttClient.builder() + .serverPort(container.getMqttPort()) + .useMqttVersion5() + .buildBlocking(); + + client.connect(); + final Mqtt5BlockingClient.Mqtt5Publishes publishes = client.publishes(MqttGlobalPublishFilter.ALL); + client.subscribeWith().topicFilter("extensions").send(); + + final Mqtt5Publish receive = publishes.receive(); + assertTrue(receive.getPayload().isPresent()); + final String extensionInfo = new String(receive.getPayloadAsBytes()); + + assertFalse(extensionInfo.contains("hivemq-allow-all-extension")); + assertFalse(extensionInfo.contains("hivemq-kafka-extension")); + assertFalse(extensionInfo.contains("hivemq-bridge-extension")); + assertFalse(extensionInfo.contains("hivemq-enterprise-security-extension")); + + container.start(); + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + public void removeKafkaExtension() throws InterruptedException { + + final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withoutPrepackagedExtensions("hivemq-kafka-extension"); + + container.start(); + + final Mqtt5BlockingClient client = MqttClient.builder() + .serverPort(container.getMqttPort()) + .useMqttVersion5() + .buildBlocking(); + + client.connect(); + final Mqtt5BlockingClient.Mqtt5Publishes publishes = client.publishes(MqttGlobalPublishFilter.ALL); + client.subscribeWith().topicFilter("extensions").send(); + + final Mqtt5Publish receive = publishes.receive(); + assertTrue(receive.getPayload().isPresent()); + final String extensionInfo = new String(receive.getPayloadAsBytes()); + + assertTrue(extensionInfo.contains("hivemq-allow-all-extension")); + assertFalse(extensionInfo.contains("hivemq-kafka-extension")); + assertTrue(extensionInfo.contains("hivemq-bridge-extension")); + assertTrue(extensionInfo.contains("hivemq-enterprise-security-extension")); + + container.stop(); + } + + public static class CheckerExtension implements ExtensionMain { + + @Override + public void extensionStart( + final @NotNull ExtensionStartInput extensionStartInput, + final @NotNull ExtensionStartOutput extensionStartOutput) { + + final String extensionFolders = Arrays.stream(extensionStartInput.getServerInformation().getExtensionsFolder().listFiles()) + .filter(File::isDirectory) + .map(File::getName) + .collect(Collectors.joining("\n")); + + final byte[] bytes = extensionFolders.getBytes(StandardCharsets.UTF_8); + Services.publishService().publish(Builders.publish() + .topic("extensions") + .retain(true) + .payload(ByteBuffer.wrap(bytes)) + .build()); + + Services.securityRegistry().setAuthenticatorProvider(authenticatorProviderInput -> + (SimpleAuthenticator) (simpleAuthInput, simpleAuthOutput) -> + simpleAuthOutput.authenticateSuccessfully()); + + } + + @Override + public void extensionStop( + final @NotNull ExtensionStopInput extensionStopInput, + final @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java new file mode 100755 index 00000000000..da9a8a9f905 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -0,0 +1,108 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Yannick Weber + */ +public class CreateFileInCopiedDirectoryIT { + + private @NotNull MountableFile createDirectory() throws IOException { + final File directory = new File(Files.createTempDirectory("").toFile(), "directory"); + assertTrue(directory.mkdir()); + final File subdirectory = new File(directory, "sub-directory"); + assertTrue(subdirectory.mkdir()); + return MountableFile.forHostPath(directory.getPath()); + } + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCreatorExtension.class).build(); + + final HiveMQContainer extension = + new HiveMQContainer() + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInHomeFolder(createDirectory(), "directory"); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + + public static class FileCreatorExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File homeFolder = extensionStartInput.getServerInformation().getHomeFolder(); + + final File dir = new File(homeFolder, "directory"); + final File dirFile = new File(dir, "file.txt"); + final File subDir = new File(dir, "sub-directory"); + final File subDirFile = new File(subDir, "file.txt"); + + try { + if (dirFile.createNewFile() && subDirFile.createNewFile()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + } catch (IOException e) { + e.printStackTrace(); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java new file mode 100755 index 00000000000..f91ba2044b6 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -0,0 +1,90 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +/** + * @author Yannick Weber + */ +public class CreateFileInExtensionDirectoryIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCreatorExtension.class).build(); + + final HiveMQContainer extension = + new HiveMQContainer() + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension); + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + + public static class FileCreatorExtension implements ExtensionMain { + + @Override + public void extensionStart(@NotNull ExtensionStartInput extensionStartInput, @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + + final File extensionHomeFolder = extensionStartInput.getExtensionInformation().getExtensionHomeFolder(); + + final File file = new File(extensionHomeFolder, "myfile.txt"); + try { + if (file.createNewFile()) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } + } catch (IOException e) { + e.printStackTrace(); + } + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(@NotNull ExtensionStopInput extensionStopInput, @NotNull ExtensionStopOutput extensionStopOutput) { + + } + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java new file mode 100644 index 00000000000..9502108a29c --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -0,0 +1,55 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Yannick Weber + */ +public class DisableEnableExtensionFromDirectoryIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQContainer extension = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension") + .withLogLevel(Level.DEBUG); + + extension.start(); + + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.disableExtension("Modifier Extension", "modifier-extension"); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(extension.getMqttPort())); + extension.enableExtension("Modifier Extension", "modifier-extension"); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + + extension.stop(); + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java new file mode 100644 index 00000000000..f4a6c529d9a --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -0,0 +1,64 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.slf4j.event.Level; +import org.testcontainers.hivemq.util.MyExtension; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Yannick Weber + */ +public class DisableEnableExtensionIT { + + private final @NotNull HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .disabledOnStartup(true) + .mainClass(MyExtension.class).build(); + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final HiveMQContainer extension = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + .withExtension(hiveMQExtension) + .withLogLevel(Level.DEBUG); + + extension.start(); + + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(extension.getMqttPort())); + extension.enableExtension(hiveMQExtension); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.disableExtension(hiveMQExtension); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(extension.getMqttPort())); + extension.enableExtension(hiveMQExtension); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + + extension.stop(); + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java new file mode 100644 index 00000000000..55b5b91f288 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java @@ -0,0 +1,59 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Yannick Weber + */ +public class DisableEnableMavenExtensionIT { + + @Test + @Timeout(value = 3, unit = TimeUnit.MINUTES) + void test() throws Exception { + final MountableFile extensionDir = new MavenHiveMQExtensionSupplier( + getClass().getResource("/maven-extension/pom.xml").getPath()) + .addProperty("HIVEMQ_GROUP_ID", "com.hivemq") + .addProperty("HIVEMQ_EXTENSION_SDK", "hivemq-extension-sdk") + .addProperty("HIVEMQ_EXTENSION_SDK_VERSION", "4.3.0") + .quiet() + .get(); + + final HiveMQContainer extension = + new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + .waitForExtension("Maven Extension") + .withExtension(extensionDir); + + extension.start(); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.disableExtension("Maven Extension", "maven-extension"); + assertThrows(ExecutionException.class, () -> TestPublishModifiedUtil.testPublishModified(extension.getMqttPort())); + extension.enableExtension("Maven Extension", "maven-extension"); + TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); + extension.stop(); + } + +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java new file mode 100644 index 00000000000..f07a4dcd800 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java @@ -0,0 +1,98 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Yannick Weber + */ +class HiveMQTestContainerCore { + + final @NotNull HiveMQContainer container = new HiveMQContainer(); + + @TempDir + File tempDir; + + @Test + void withExtension_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withExtension(mountableFile)); + } + + @Test + void withExtension_fileNoDirectory_Exception() throws IOException { + final File extension = new File(tempDir, "extension"); + assertTrue(extension.createNewFile()); + final MountableFile mountableFile = MountableFile.forHostPath(extension.getAbsolutePath()); + assertThrows(ContainerLaunchException.class, () -> container.withExtension(mountableFile)); + } + + @Test + void withLicense_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withLicense(mountableFile)); + } + + @Test + void withExtension_fileEndingWrong_Exception() throws IOException { + final File extension = new File(tempDir, "extension.wrong"); + assertTrue(extension.createNewFile()); + final MountableFile mountableFile = MountableFile.forHostPath(extension.getAbsolutePath()); + assertThrows(ContainerLaunchException.class, () -> container.withLicense(mountableFile)); + } + + @Test + void withHiveMQConfig_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withHiveMQConfig(mountableFile)); + } + + @Test + void withFileInHomeFolder_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withFileInHomeFolder(mountableFile, "some/path")); + } + + @Test + void withFileInHomeFolder_pathEmpty_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withFileInHomeFolder(mountableFile, "")); + } + + @Test + void withFileInExtensionHomeFolder_withPath_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withFileInExtensionHomeFolder(mountableFile, "my-extension", "some/path")); + } + + @Test + void withFileInExtensionHomeFolder_fileDoesNotExist_Exception() { + final MountableFile mountableFile = MountableFile.forHostPath("/this/does/not/exist"); + assertThrows(ContainerLaunchException.class, () -> container.withFileInExtensionHomeFolder(mountableFile, "my-extension")); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java new file mode 100755 index 00000000000..3ca3f74384f --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Yannick Weber + */ +class PathUtilTest { + + @Test + void prepareInnerPath_emptyString() { + assertEquals("/", PathUtil.prepareInnerPath("")); + } + + @Test + void prepareInnerPath_onlyDelimiter() { + assertEquals("/", PathUtil.prepareInnerPath("/")); + } + + @Test + void prepareInnerPath_noDelimiter() { + assertEquals("/path/", PathUtil.prepareInnerPath("path")); + } + + @Test + void prepareInnerPath_delimiterAtEnd() { + assertEquals("/path/", PathUtil.prepareInnerPath("path/")); + } + + @Test + void prepareInnerPath_delimiterAtBeginning() { + assertEquals("/path/", PathUtil.prepareInnerPath("/path")); + } + + @Test + void prepareAppendPath_delimiterAtBeginning_noChange() { + assertEquals("/path", PathUtil.prepareAppendPath("/path")); + } + + @Test + void prepareAppendPath_delimiterAtBeginning_delimiterAdded() { + assertEquals("/path", PathUtil.prepareAppendPath("path")); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java new file mode 100755 index 00000000000..449cbb7dcad --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java @@ -0,0 +1,55 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq.util; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import org.jetbrains.annotations.NotNull; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +/** + * @author Yannick Weber + */ +@SuppressWarnings("CodeBlock2Expr") +public class MyExtension implements ExtensionMain { + + @Override + public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java new file mode 100755 index 00000000000..f6cffea25c2 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq.util; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import org.jetbrains.annotations.NotNull; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStartOutput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopInput; +import com.hivemq.extension.sdk.api.parameter.ExtensionStopOutput; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; + +/** + * @author Yannick Weber + */ +public class MyExtensionWithSubclasses implements ExtensionMain { + + @Override + public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> clientContext.addPublishInboundInterceptor(new PublishModifier()); + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { + + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java new file mode 100755 index 00000000000..87ec0f77ef5 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java @@ -0,0 +1,34 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq.util; + +import org.jetbrains.annotations.NotNull; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundInput; +import com.hivemq.extension.sdk.api.interceptor.publish.parameter.PublishInboundOutput; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +/** + * @author Yannick Weber + */ +public class PublishModifier implements PublishInboundInterceptor { + @Override + public void onInboundPublish(final @NotNull PublishInboundInput publishInboundInput, final @NotNull PublishInboundOutput publishInboundOutput) { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java new file mode 100755 index 00000000000..02a38d057e9 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java @@ -0,0 +1,66 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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.testcontainers.hivemq.util; + +import com.hivemq.client.mqtt.MqttGlobalPublishFilter; +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +/** + * @author Yannick Weber + */ +public class TestPublishModifiedUtil { + + public static void testPublishModified(final int mqttPort) throws InterruptedException, ExecutionException { + final CompletableFuture publishReceived = new CompletableFuture<>(); + + final Mqtt5BlockingClient publisher = Mqtt5Client.builder() + .serverPort(mqttPort) + .identifier("publisher") + .buildBlocking(); + publisher.connect(); + + final Mqtt5BlockingClient subscriber = Mqtt5Client.builder() + .serverPort(mqttPort) + .identifier("subscriber") + .buildBlocking(); + subscriber.connect(); + subscriber.subscribeWith().topicFilter("test/topic").send(); + subscriber.toAsync().publishes(MqttGlobalPublishFilter.ALL, publish -> { + if (Arrays.equals(publish.getPayloadAsBytes(), "modified".getBytes(StandardCharsets.UTF_8))) { + publishReceived.complete(null); + } else { + publishReceived.completeExceptionally(new IllegalArgumentException("unexpected payload: " + new String(publish.getPayloadAsBytes()))); + } + }); + + publisher.publishWith().topic("test/topic").payload("unmodified".getBytes(StandardCharsets.UTF_8)).send(); + + try { + publishReceived.get(); + } finally { + publisher.disconnect(); + subscriber.disconnect(); + } + } + + +} diff --git a/modules/hivemq/src/test/resources/additionalFile.txt b/modules/hivemq/src/test/resources/additionalFile.txt new file mode 100755 index 00000000000..7773653a4f8 --- /dev/null +++ b/modules/hivemq/src/test/resources/additionalFile.txt @@ -0,0 +1,16 @@ +==== + Copyright 2020 HiveMQ and the HiveMQ Community + + Licensed 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. +==== + diff --git a/modules/hivemq/src/test/resources/config.xml b/modules/hivemq/src/test/resources/config.xml new file mode 100755 index 00000000000..5210e0c18df --- /dev/null +++ b/modules/hivemq/src/test/resources/config.xml @@ -0,0 +1,32 @@ + + + + + + + 1883 + 0.0.0.0 + + + + + 0 + + + diff --git a/modules/hivemq/src/test/resources/gradle-extension/build.gradle b/modules/hivemq/src/test/resources/gradle-extension/build.gradle new file mode 100644 index 00000000000..f306097c6c9 --- /dev/null +++ b/modules/hivemq/src/test/resources/gradle-extension/build.gradle @@ -0,0 +1,32 @@ +/** + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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. + */ +plugins { + id 'java' + id 'com.hivemq.extension' +} + +group 'org.example' +version '1.0.0' + +hivemqExtension { + name = 'Gradle Extension' + author = 'Example Org' + priority = 0 + startPriority = 1000 + mainClass = 'com.hivemq.MyExtension' + sdkVersion = '4.4.1' +} + diff --git a/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.jar b/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties b/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..cba5f90b0b8 --- /dev/null +++ b/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,21 @@ +# +# Copyright 2020 HiveMQ and the HiveMQ Community +# +# Licensed 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. +# + +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/modules/hivemq/src/test/resources/gradle-extension/gradlew b/modules/hivemq/src/test/resources/gradle-extension/gradlew new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modules/hivemq/src/test/resources/gradle-extension/gradlew.bat b/modules/hivemq/src/test/resources/gradle-extension/gradlew.bat new file mode 100644 index 00000000000..606810ce664 --- /dev/null +++ b/modules/hivemq/src/test/resources/gradle-extension/gradlew.bat @@ -0,0 +1,105 @@ +@REM +@REM Copyright 2020 HiveMQ and the HiveMQ Community +@REM +@REM Licensed under the Apache License, Version 2.0 (the "License"); +@REM you may not use this file except in compliance with the License. +@REM You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, software +@REM distributed under the License is distributed on an "AS IS" BASIS, +@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@REM See the License for the specific language governing permissions and +@REM limitations under the License. +@REM + +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/modules/hivemq/src/test/resources/gradle-extension/settings.gradle b/modules/hivemq/src/test/resources/gradle-extension/settings.gradle new file mode 100644 index 00000000000..d2754d9b5e7 --- /dev/null +++ b/modules/hivemq/src/test/resources/gradle-extension/settings.gradle @@ -0,0 +1,21 @@ +/** + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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. + */ +pluginManagement { + plugins { + id 'com.hivemq.extension' version '2.0.0' + } +} +rootProject.name = 'gradle-extension' diff --git a/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java b/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java new file mode 100644 index 00000000000..88b3f7a8487 --- /dev/null +++ b/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java @@ -0,0 +1,56 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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 com.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.annotations.NotNull; +import com.hivemq.extension.sdk.api.events.EventRegistry; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.*; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +/** + * @author Yannick Weber + */ +@SuppressWarnings("CodeBlock2Expr") +public class MyExtension implements ExtensionMain { + + @Override + public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { + + } +} diff --git a/modules/hivemq/src/test/resources/logback-test.xml b/modules/hivemq/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..c020cde75fe --- /dev/null +++ b/modules/hivemq/src/test/resources/logback-test.xml @@ -0,0 +1,39 @@ + + + + + + %-30(%d %level)- %msg%n%ex + + + + + + + + + + + + + + + + + diff --git a/modules/hivemq/src/test/resources/maven-extension/assembly.xml b/modules/hivemq/src/test/resources/maven-extension/assembly.xml new file mode 100644 index 00000000000..632d86ff39e --- /dev/null +++ b/modules/hivemq/src/test/resources/maven-extension/assembly.xml @@ -0,0 +1,39 @@ + + + + distribution + + zip + + + + src/main/resources/hivemq-extension.xml + /${artifactId}/ + true + + + target/${artifactId}-${version}.jar + ${artifactId}-${version}.jar + /${artifactId}/ + + + false + diff --git a/modules/hivemq/src/test/resources/maven-extension/pom.xml b/modules/hivemq/src/test/resources/maven-extension/pom.xml new file mode 100644 index 00000000000..02ad7ae6103 --- /dev/null +++ b/modules/hivemq/src/test/resources/maven-extension/pom.xml @@ -0,0 +1,104 @@ + + + + 4.0.0 + + com.hivemq + maven-extension + 1.0.0 + + + Maven Extension + HiveMQ GmbH + + + + + com.hivemq + hivemq-extension-sdk + 4.3.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + 11 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.1 + + + package + + shade + + + + + com.hivemq:hivemq-extension-sdk + org.slf4j:* + ch.qos.logback:* + javax.servlet:* + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + maven-assembly-plugin + + + assembly + package + + single + + + + assembly.xml + + + + + + + + + diff --git a/modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java b/modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java new file mode 100644 index 00000000000..88b3f7a8487 --- /dev/null +++ b/modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java @@ -0,0 +1,56 @@ +/* + * Copyright 2020 HiveMQ and the HiveMQ Community + * + * Licensed 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 com.hivemq; + +import com.hivemq.extension.sdk.api.ExtensionMain; +import com.hivemq.extension.sdk.api.annotations.NotNull; +import com.hivemq.extension.sdk.api.events.EventRegistry; +import com.hivemq.extension.sdk.api.interceptor.publish.PublishInboundInterceptor; +import com.hivemq.extension.sdk.api.parameter.*; +import com.hivemq.extension.sdk.api.services.Services; +import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +/** + * @author Yannick Weber + */ +@SuppressWarnings("CodeBlock2Expr") +public class MyExtension implements ExtensionMain { + + @Override + public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) { + + final PublishInboundInterceptor publishInboundInterceptor = (publishInboundInput, publishInboundOutput) -> { + publishInboundOutput.getPublishPacket().setPayload(ByteBuffer.wrap("modified".getBytes(StandardCharsets.UTF_8))); + }; + + final ClientInitializer clientInitializer = (initializerInput, clientContext) -> { + clientContext.addPublishInboundInterceptor(publishInboundInterceptor); + }; + + Services.initializerRegistry().setClientInitializer(clientInitializer); + } + + @Override + public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) { + + } +} diff --git a/modules/hivemq/src/test/resources/maven-extension/src/main/resources/META-INF/services/com.hivemq.extension.sdk.api.ExtensionMain b/modules/hivemq/src/test/resources/maven-extension/src/main/resources/META-INF/services/com.hivemq.extension.sdk.api.ExtensionMain new file mode 100644 index 00000000000..243ec023a5b --- /dev/null +++ b/modules/hivemq/src/test/resources/maven-extension/src/main/resources/META-INF/services/com.hivemq.extension.sdk.api.ExtensionMain @@ -0,0 +1 @@ +com.hivemq.MyExtension diff --git a/modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml b/modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml new file mode 100644 index 00000000000..d0e98b6c4fc --- /dev/null +++ b/modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml @@ -0,0 +1,25 @@ + + + + ${artifactId} + ${version} + ${extension.name} + ${extension.author} + 1000 + diff --git a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml new file mode 100755 index 00000000000..f1691aaed18 --- /dev/null +++ b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml @@ -0,0 +1,25 @@ + + + + modifier-extension + 1.0-SNAPSHOT + Modifier Extension + HiveMQ GmbH + 1000 + diff --git a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/modifier-extension-1.0-SNAPSHOT.jar b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/modifier-extension-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..18a7ea85f53dcf856d5280676386448b43d2d537 GIT binary patch literal 102179 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
= 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 z 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 + + + modifier-extension + 1.0-SNAPSHOT + Modifier Extension + HiveMQ GmbH + 1000 + diff --git a/modules/hivemq/src/test/resources/modifier-extension/modifier-extension-1.0-SNAPSHOT.jar b/modules/hivemq/src/test/resources/modifier-extension/modifier-extension-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..18a7ea85f53dcf856d5280676386448b43d2d537 GIT binary patch literal 102179 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
= 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 z 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 Date: Mon, 29 Nov 2021 12:55:51 +0100 Subject: [PATCH 02/30] updated licensing --- modules/hivemq/HEADER | 21 ++ modules/hivemq/build.gradle.kts | 13 +- modules/hivemq/gradle.properties | 4 - modules/hivemq/settings.gradle.kts | 1 + .../hivemq/GradleHiveMQExtensionSupplier.java | 28 ++- .../hivemq/HiveMQContainer.java | 28 ++- .../hivemq/HiveMQExtension.java | 28 ++- .../hivemq/MavenHiveMQExtensionSupplier.java | 28 ++- .../hivemq/MultiLogMessageWaitStrategy.java | 28 ++- .../org/testcontainers/hivemq/PathUtil.java | 28 ++- .../hivemq/ContainerWithControlCenterIT.java | 28 ++- .../hivemq/ContainerWithCustomConfigIT.java | 28 ++- ...ContainerWithExtensionFromDirectoryIT.java | 28 ++- .../hivemq/ContainerWithExtensionIT.java | 28 ++- .../ContainerWithExtensionSubclassIT.java | 28 ++- .../ContainerWithFileInExtensionHomeIT.java | 28 ++- .../hivemq/ContainerWithFileInHomeIT.java | 28 ++- .../ContainerWithGradleExtensionIT.java | 28 ++- .../hivemq/ContainerWithLicenseIT.java | 28 ++- .../hivemq/ContainerWithMavenExtensionIT.java | 28 ++- .../ContainerWithoutPlatformExtensionsIT.java | 28 ++- .../hivemq/CreateFileInCopiedDirectoryIT.java | 28 ++- .../CreateFileInExtensionDirectoryIT.java | 28 ++- ...DisableEnableExtensionFromDirectoryIT.java | 28 ++- .../hivemq/DisableEnableExtensionIT.java | 28 ++- .../hivemq/DisableEnableMavenExtensionIT.java | 28 ++- .../hivemq/HiveMQTestContainerCore.java | 28 ++- .../testcontainers/hivemq/PathUtilTest.java | 28 ++- .../hivemq/util/MyExtension.java | 28 ++- .../util/MyExtensionWithSubclasses.java | 28 ++- .../hivemq/util/PublishModifier.java | 28 ++- .../hivemq/util/TestPublishModifiedUtil.java | 28 ++- .../src/test/resources/additionalFile.txt | 28 ++- modules/hivemq/src/test/resources/config.xml | 28 ++- .../resources/gradle-extension/build.gradle | 30 ++- .../gradle/wrapper/gradle-wrapper.properties | 18 +- .../test/resources/gradle-extension/gradlew | 234 ++++++++++++++++++ .../resources/gradle-extension/gradlew.bat | 16 -- .../gradle-extension/settings.gradle | 28 ++- .../src/main/java/com/hivemq/MyExtension.java | 29 ++- .../src/test/resources/logback-test.xml | 34 ++- .../resources/maven-extension/assembly.xml | 28 ++- .../test/resources/maven-extension/pom.xml | 28 ++- .../src/main/java/com/hivemq/MyExtension.java | 29 ++- .../src/main/resources/hivemq-extension.xml | 28 ++- .../hivemq-extension.xml | 28 ++- .../modifier-extension/hivemq-extension.xml | 28 ++- 47 files changed, 993 insertions(+), 444 deletions(-) create mode 100644 modules/hivemq/HEADER create mode 100644 modules/hivemq/settings.gradle.kts mode change 100644 => 100755 modules/hivemq/src/test/resources/gradle-extension/gradlew diff --git a/modules/hivemq/HEADER b/modules/hivemq/HEADER new file mode 100644 index 00000000000..f016729ce96 --- /dev/null +++ b/modules/hivemq/HEADER @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021-present HiveMQ GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index e190d3e0f5e..c219ff7e623 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -1,4 +1,9 @@ -description = "Core API for testing HiveMQ Extensions and Java MQTT Applications." +description = "Core API for testing MQTT Applications." + +plugins { + `java-library` + id("com.github.hierynomus.license") version "0.16.1" +} dependencies { api(project(":testcontainers")) @@ -36,3 +41,9 @@ dependencies { tasks.withType { useJUnitPlatform() } + +license { + header = projectDir.resolve("HEADER") + mapping("java", "SLASHSTAR_STYLE") + excludes(mutableListOf("gradle-wrapper.properties", "gradlew", "gradlew.bat")) +} diff --git a/modules/hivemq/gradle.properties b/modules/hivemq/gradle.properties index 0dbcbbf3223..9ddbe187464 100644 --- a/modules/hivemq/gradle.properties +++ b/modules/hivemq/gradle.properties @@ -20,7 +20,3 @@ hivemq-mqtt-client.version=1.2.2 httpclient.version=4.5.13 logback.version=1.2.3 junit5.version=5.8.1 -# -# plugins -# -plugin.nexus-publish.version=1.1.0 diff --git a/modules/hivemq/settings.gradle.kts b/modules/hivemq/settings.gradle.kts new file mode 100644 index 00000000000..f3d5bcba948 --- /dev/null +++ b/modules/hivemq/settings.gradle.kts @@ -0,0 +1 @@ +include(":testcontainers") diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java index 458ab02dd9d..d34bd779d62 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index c09ecf58b4d..2ae5b2fb509 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java index 954cbf35cf9..5dfa79c7187 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java index d4f8e5d5582..6508232a724 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java index 82bf87df9c6..186f51b026f 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java index bca4609e0e9..3dfe7973a83 100755 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java index 92819a0b27f..68e6db09ba4 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java index 0d8495787b2..24a70de160c 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java index 421826fd1f7..5e99fb0b11d 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java index bc87e204947..5478b816821 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java index a5dbb095cec..08860931558 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java index eb8e7cd05a3..359fda2ad86 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java index b2749c790c2..d622e81ad8f 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java index c399ceebfcf..b4d642308a3 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java index ad195f9dd7a..c1dc243a060 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java index 499196a3c7e..d8f1df1ac4e 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java index ed024ff9079..31bb8e30376 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java index da9a8a9f905..09142f68e8e 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java index f91ba2044b6..d4fea3b3185 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java index 9502108a29c..17a5f5dd5ea 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java index f4a6c529d9a..c1b345d52ba 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java index 55b5b91f288..405bc65ee54 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java index f07a4dcd800..2b520615ddf 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java index 3ca3f74384f..d5d2cdb419d 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java index 449cbb7dcad..b3261bcb911 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq.util; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java index f6cffea25c2..33f2625b7b2 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq.util; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java index 87ec0f77ef5..2c2dfaaa147 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq.util; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java index 02a38d057e9..209bf3dbbea 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java @@ -1,17 +1,25 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package org.testcontainers.hivemq.util; diff --git a/modules/hivemq/src/test/resources/additionalFile.txt b/modules/hivemq/src/test/resources/additionalFile.txt index 7773653a4f8..f59c5b3e6e8 100755 --- a/modules/hivemq/src/test/resources/additionalFile.txt +++ b/modules/hivemq/src/test/resources/additionalFile.txt @@ -1,16 +1,24 @@ ==== - Copyright 2020 HiveMQ and the HiveMQ Community + MIT License - Licensed 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 + Copyright (c) 2021-present HiveMQ GmbH - http://www.apache.org/licenses/LICENSE-2.0 + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: - 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. + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. ==== diff --git a/modules/hivemq/src/test/resources/config.xml b/modules/hivemq/src/test/resources/config.xml index 5210e0c18df..e74cd80784e 100755 --- a/modules/hivemq/src/test/resources/config.xml +++ b/modules/hivemq/src/test/resources/config.xml @@ -1,19 +1,27 @@ diff --git a/modules/hivemq/src/test/resources/gradle-extension/build.gradle b/modules/hivemq/src/test/resources/gradle-extension/build.gradle index f306097c6c9..d698ead39fd 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/build.gradle +++ b/modules/hivemq/src/test/resources/gradle-extension/build.gradle @@ -1,17 +1,25 @@ -/** - * Copyright 2020 HiveMQ and the HiveMQ Community +/* + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ plugins { id 'java' diff --git a/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties b/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties index cba5f90b0b8..e750102e092 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties +++ b/modules/hivemq/src/test/resources/gradle-extension/gradle/wrapper/gradle-wrapper.properties @@ -1,21 +1,5 @@ -# -# Copyright 2020 HiveMQ and the HiveMQ Community -# -# Licensed 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. -# - distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/modules/hivemq/src/test/resources/gradle-extension/gradlew b/modules/hivemq/src/test/resources/gradle-extension/gradlew old mode 100644 new mode 100755 index e69de29bb2d..3da45c161b0 --- a/modules/hivemq/src/test/resources/gradle-extension/gradlew +++ b/modules/hivemq/src/test/resources/gradle-extension/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright ? 2015-2021 the original authors. +# +# Licensed 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?, +# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?; +# * compound commands having a testable exit status, especially ?case?; +# * various built-in commands including ?command?, ?set?, and ?ulimit?. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/modules/hivemq/src/test/resources/gradle-extension/gradlew.bat b/modules/hivemq/src/test/resources/gradle-extension/gradlew.bat index 606810ce664..107acd32c4e 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/gradlew.bat +++ b/modules/hivemq/src/test/resources/gradle-extension/gradlew.bat @@ -1,19 +1,3 @@ -@REM -@REM Copyright 2020 HiveMQ and the HiveMQ Community -@REM -@REM Licensed under the Apache License, Version 2.0 (the "License"); -@REM you may not use this file except in compliance with the License. -@REM You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, software -@REM distributed under the License is distributed on an "AS IS" BASIS, -@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@REM See the License for the specific language governing permissions and -@REM limitations under the License. -@REM - @rem @rem Copyright 2015 the original author or authors. @rem diff --git a/modules/hivemq/src/test/resources/gradle-extension/settings.gradle b/modules/hivemq/src/test/resources/gradle-extension/settings.gradle index d2754d9b5e7..1cf9e116c10 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/settings.gradle +++ b/modules/hivemq/src/test/resources/gradle-extension/settings.gradle @@ -1,17 +1,25 @@ /** - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ pluginManagement { plugins { diff --git a/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java b/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java index 88b3f7a8487..be716fd408e 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java +++ b/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java @@ -1,19 +1,26 @@ /* - * Copyright 2020 HiveMQ and the HiveMQ Community + * MIT License * - * Licensed 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 + * Copyright (c) 2021-present HiveMQ GmbH * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - package com.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/resources/logback-test.xml b/modules/hivemq/src/test/resources/logback-test.xml index c020cde75fe..88800b8f0e9 100644 --- a/modules/hivemq/src/test/resources/logback-test.xml +++ b/modules/hivemq/src/test/resources/logback-test.xml @@ -1,18 +1,26 @@ diff --git a/modules/hivemq/src/test/resources/maven-extension/assembly.xml b/modules/hivemq/src/test/resources/maven-extension/assembly.xml index 632d86ff39e..3bb8cb8752a 100644 --- a/modules/hivemq/src/test/resources/maven-extension/assembly.xml +++ b/modules/hivemq/src/test/resources/maven-extension/assembly.xml @@ -1,19 +1,27 @@ diff --git a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml index f1691aaed18..df55dfa9d82 100755 --- a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml +++ b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml @@ -1,19 +1,27 @@ diff --git a/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml b/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml index f1691aaed18..df55dfa9d82 100755 --- a/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml +++ b/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml @@ -1,19 +1,27 @@ From b63c38397a73149b85b46152d261cd9ab88f0e7d Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 29 Nov 2021 13:09:09 +0100 Subject: [PATCH 03/30] added license exclusions to build.gradle.kts --- modules/hivemq/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index c219ff7e623..50762559a87 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { testImplementation("com.hivemq:hivemq-extension-sdk:${property("hivemq-extension-sdk.version")}") testImplementation("com.hivemq:hivemq-mqtt-client:${property("hivemq-mqtt-client.version")}") testImplementation("org.apache.httpcomponents:httpclient:${property("httpclient.version")}") - testImplementation("ch.qos.logback:logback-classic:${property("logback.version")}") + testImplementation("ch.qos.logback:logback-classic:${property("logback.version")}") k } @@ -45,5 +45,5 @@ tasks.withType { license { header = projectDir.resolve("HEADER") mapping("java", "SLASHSTAR_STYLE") - excludes(mutableListOf("gradle-wrapper.properties", "gradlew", "gradlew.bat")) + excludes(mutableListOf("**/gradle-wrapper.properties", "**/gradlew", "**/gradlew.bat")) } From ff47353984c9fa32775c657099acd10b7316fbae Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 29 Nov 2021 13:09:25 +0100 Subject: [PATCH 04/30] fixed build.gradle.kts --- modules/hivemq/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index 50762559a87..1bedde845e9 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { testImplementation("com.hivemq:hivemq-extension-sdk:${property("hivemq-extension-sdk.version")}") testImplementation("com.hivemq:hivemq-mqtt-client:${property("hivemq-mqtt-client.version")}") testImplementation("org.apache.httpcomponents:httpclient:${property("httpclient.version")}") - testImplementation("ch.qos.logback:logback-classic:${property("logback.version")}") k + testImplementation("ch.qos.logback:logback-classic:${property("logback.version")}") } From 81c57ce4488619c07a11cdac57562ffe2f655635 Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 29 Nov 2021 13:11:04 +0100 Subject: [PATCH 05/30] removed unnecessary schema declarations --- .../hivemq/src/test/resources/maven-extension/assembly.xml | 4 +--- modules/hivemq/src/test/resources/maven-extension/pom.xml | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/hivemq/src/test/resources/maven-extension/assembly.xml b/modules/hivemq/src/test/resources/maven-extension/assembly.xml index 3bb8cb8752a..c252199af28 100644 --- a/modules/hivemq/src/test/resources/maven-extension/assembly.xml +++ b/modules/hivemq/src/test/resources/maven-extension/assembly.xml @@ -24,9 +24,7 @@ SOFTWARE. --> - + distribution zip diff --git a/modules/hivemq/src/test/resources/maven-extension/pom.xml b/modules/hivemq/src/test/resources/maven-extension/pom.xml index 74952ead7a8..dfe7751cfee 100644 --- a/modules/hivemq/src/test/resources/maven-extension/pom.xml +++ b/modules/hivemq/src/test/resources/maven-extension/pom.xml @@ -24,8 +24,7 @@ SOFTWARE. --> - + 4.0.0 com.hivemq From df4b1e786c66efc45ba16da73e0f60db8c157305 Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 29 Nov 2021 13:15:47 +0100 Subject: [PATCH 06/30] added constants for default images and added them to test --- .../testcontainers/hivemq/HiveMQContainer.java | 7 ++++--- .../hivemq/ContainerWithControlCenterIT.java | 2 +- .../hivemq/ContainerWithCustomConfigIT.java | 16 ++++++++-------- .../ContainerWithoutPlatformExtensionsIT.java | 4 ++-- .../DisableEnableExtensionFromDirectoryIT.java | 2 +- .../hivemq/DisableEnableExtensionIT.java | 2 +- .../hivemq/DisableEnableMavenExtensionIT.java | 2 +- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 2ae5b2fb509..35380998884 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -72,9 +72,10 @@ public class HiveMQContainer extends GenericContainer { " %s" + // ""; - private static final @NotNull DockerImageName DEFAULT_HIVEMQ_CE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq-ce"); - private static final @NotNull DockerImageName DEFAULT_HIVEMQ_EE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq4"); - private static final @NotNull String DEFAULT_HIVEMQ_CE_TAG = "2021.3"; + public static final @NotNull DockerImageName DEFAULT_HIVEMQ_CE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq-ce"); + public static final @NotNull DockerImageName DEFAULT_HIVEMQ_EE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq4"); + public static final @NotNull String DEFAULT_HIVEMQ_CE_TAG = "2021.3"; + public static final @NotNull String DEFAULT_HIVEMQ_EE_TAG = "4.7.2"; public static final int DEBUGGING_PORT = 9000; public static final int MQTT_PORT = 1883; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java index 68e6db09ba4..49429550943 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -45,7 +45,7 @@ public class ContainerWithControlCenterIT { public void test() throws Exception { final HiveMQContainer extension = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) .withControlCenter(); extension.start(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java index 24a70de160c..f68339eaa89 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -44,24 +44,24 @@ public class ContainerWithCustomConfigIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQContainer extension = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) - .withHiveMQConfig(MountableFile.forClasspathResource("/config.xml")); + final HiveMQContainer extension = new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + .withHiveMQConfig(MountableFile.forClasspathResource("/config.xml")); extension.start(); final Mqtt5BlockingClient publisher = Mqtt5Client.builder() - .identifier("publisher") - .serverPort(extension.getMqttPort()) - .buildBlocking(); + .identifier("publisher") + .serverPort(extension.getMqttPort()) + .buildBlocking(); publisher.connect(); assertThrows(MqttSessionExpiredException.class, () -> { // this should fail since only QoS 0 is allowed by the configuration publisher.publishWith() - .topic("test/topic") - .qos(MqttQos.EXACTLY_ONCE) - .send(); + .topic("test/topic") + .qos(MqttQos.EXACTLY_ONCE) + .send(); }); extension.stop(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java index 31bb8e30376..cf68b392194 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -66,7 +66,7 @@ public class ContainerWithoutPlatformExtensionsIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) public void removeAllPlatformExtensions() throws InterruptedException { - final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + final HiveMQContainer container = new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) .withExtension(hiveMQExtension) .waitForExtension(hiveMQExtension) .withoutPrepackagedExtensions(); @@ -98,7 +98,7 @@ public void removeAllPlatformExtensions() throws InterruptedException { @Timeout(value = 3, unit = TimeUnit.MINUTES) public void removeKafkaExtension() throws InterruptedException { - final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) .withExtension(hiveMQExtension) .waitForExtension(hiveMQExtension) .withoutPrepackagedExtensions("hivemq-kafka-extension"); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java index 17a5f5dd5ea..533467d51de 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -44,7 +44,7 @@ public class DisableEnableExtensionFromDirectoryIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQContainer extension = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) .withExtension(MountableFile.forClasspathResource("/modifier-extension")) .waitForExtension("Modifier Extension") .withLogLevel(Level.DEBUG); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java index c1b345d52ba..b8021a7b2a4 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -52,7 +52,7 @@ public class DisableEnableExtensionIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQContainer extension = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) .withExtension(hiveMQExtension) .withLogLevel(Level.DEBUG); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java index 405bc65ee54..46477fa291f 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java @@ -51,7 +51,7 @@ void test() throws Exception { .get(); final HiveMQContainer extension = - new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag("latest")) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) .waitForExtension("Maven Extension") .withExtension(extensionDir); From e2f81f1a4d980bb6d2849988baa9caaf258b8213 Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 29 Nov 2021 13:18:38 +0100 Subject: [PATCH 07/30] improved constants --- .../java/org/testcontainers/hivemq/HiveMQContainer.java | 6 +++--- .../testcontainers/hivemq/ContainerWithControlCenterIT.java | 2 +- .../testcontainers/hivemq/ContainerWithCustomConfigIT.java | 2 +- .../hivemq/ContainerWithoutPlatformExtensionsIT.java | 4 ++-- .../hivemq/DisableEnableExtensionFromDirectoryIT.java | 2 +- .../org/testcontainers/hivemq/DisableEnableExtensionIT.java | 2 +- .../hivemq/DisableEnableMavenExtensionIT.java | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 35380998884..f20ed843cd8 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -72,10 +72,10 @@ public class HiveMQContainer extends GenericContainer { " %s" + // ""; - public static final @NotNull DockerImageName DEFAULT_HIVEMQ_CE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq-ce"); - public static final @NotNull DockerImageName DEFAULT_HIVEMQ_EE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq4"); - public static final @NotNull String DEFAULT_HIVEMQ_CE_TAG = "2021.3"; public static final @NotNull String DEFAULT_HIVEMQ_EE_TAG = "4.7.2"; + public static final @NotNull String DEFAULT_HIVEMQ_CE_TAG = "2021.3"; + public static final @NotNull DockerImageName DEFAULT_HIVEMQ_EE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq4").withTag(DEFAULT_HIVEMQ_EE_TAG); + public static final @NotNull DockerImageName DEFAULT_HIVEMQ_CE_IMAGE_NAME = DockerImageName.parse("hivemq/hivemq-ce").withTag(DEFAULT_HIVEMQ_CE_TAG); public static final int DEBUGGING_PORT = 9000; public static final int MQTT_PORT = 1883; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java index 49429550943..7d608717103 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -45,7 +45,7 @@ public class ContainerWithControlCenterIT { public void test() throws Exception { final HiveMQContainer extension = - new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME) .withControlCenter(); extension.start(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java index f68339eaa89..8b002ae11a1 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -44,7 +44,7 @@ public class ContainerWithCustomConfigIT { @Test @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { - final HiveMQContainer extension = new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + final HiveMQContainer extension = new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME) .withHiveMQConfig(MountableFile.forClasspathResource("/config.xml")); extension.start(); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java index cf68b392194..1a446939995 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -66,7 +66,7 @@ public class ContainerWithoutPlatformExtensionsIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) public void removeAllPlatformExtensions() throws InterruptedException { - final HiveMQContainer container = new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + final HiveMQContainer container = new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME) .withExtension(hiveMQExtension) .waitForExtension(hiveMQExtension) .withoutPrepackagedExtensions(); @@ -98,7 +98,7 @@ public void removeAllPlatformExtensions() throws InterruptedException { @Timeout(value = 3, unit = TimeUnit.MINUTES) public void removeKafkaExtension() throws InterruptedException { - final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq4").withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + final HiveMQContainer container = new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME) .withExtension(hiveMQExtension) .waitForExtension(hiveMQExtension) .withoutPrepackagedExtensions("hivemq-kafka-extension"); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java index 533467d51de..d1b060290af 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -44,7 +44,7 @@ public class DisableEnableExtensionFromDirectoryIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQContainer extension = - new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME) .withExtension(MountableFile.forClasspathResource("/modifier-extension")) .waitForExtension("Modifier Extension") .withLogLevel(Level.DEBUG); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java index b8021a7b2a4..69c0d811bc7 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -52,7 +52,7 @@ public class DisableEnableExtensionIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQContainer extension = - new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME) .withExtension(hiveMQExtension) .withLogLevel(Level.DEBUG); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java index 46477fa291f..c846893a531 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java @@ -51,7 +51,7 @@ void test() throws Exception { .get(); final HiveMQContainer extension = - new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME.withTag(HiveMQContainer.DEFAULT_HIVEMQ_EE_TAG)) + new HiveMQContainer(HiveMQContainer.DEFAULT_HIVEMQ_EE_IMAGE_NAME) .waitForExtension("Maven Extension") .withExtension(extensionDir); From d67d46ca8e9b7b0a50d68c0b471836d4f16e241b Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 29 Nov 2021 13:29:22 +0100 Subject: [PATCH 08/30] using in memory persistence for ITs --- ...ContainerWithExtensionFromDirectoryIT.java | 17 +++++++++-------- .../hivemq/ContainerWithExtensionIT.java | 16 +++++++++------- .../ContainerWithExtensionSubclassIT.java | 18 ++++++++++-------- .../ContainerWithFileInExtensionHomeIT.java | 1 + .../hivemq/ContainerWithFileInHomeIT.java | 19 ++++++++++--------- .../ContainerWithGradleExtensionIT.java | 9 +++++---- .../hivemq/ContainerWithLicenseIT.java | 19 ++++++++++--------- .../hivemq/ContainerWithMavenExtensionIT.java | 15 ++++++++------- .../hivemq/CreateFileInCopiedDirectoryIT.java | 9 +++++---- .../CreateFileInExtensionDirectoryIT.java | 16 +++++++++------- .../src/test/resources/inMemoryConfig.xml | 6 ++++++ 11 files changed, 82 insertions(+), 63 deletions(-) create mode 100644 modules/hivemq/src/test/resources/inMemoryConfig.xml diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java index 5e99fb0b11d..07b80792795 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -40,10 +40,11 @@ public class ContainerWithExtensionFromDirectoryIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQContainer extension = - new HiveMQContainer() - .withExtension(MountableFile.forClasspathResource("/modifier-extension")) - .waitForExtension("Modifier Extension") - .withLogLevel(Level.DEBUG); + new HiveMQContainer() + .withExtension(MountableFile.forClasspathResource("/modifier-extension")) + .waitForExtension("Modifier Extension") + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withLogLevel(Level.DEBUG); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); @@ -54,10 +55,10 @@ void test() throws Exception { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test_wrongDirectoryName() throws Exception { final HiveMQContainer extension = - new HiveMQContainer() - .withExtension(MountableFile.forClasspathResource("/modifier-extension-wrong-name")) - .waitForExtension("Modifier Extension") - .withLogLevel(Level.DEBUG); + new HiveMQContainer() + .withExtension(MountableFile.forClasspathResource("/modifier-extension-wrong-name")) + .waitForExtension("Modifier Extension") + .withLogLevel(Level.DEBUG); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java index 5478b816821..a36d85fdd28 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.Timeout; import org.testcontainers.hivemq.util.MyExtension; import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; import java.util.concurrent.TimeUnit; @@ -39,15 +40,16 @@ public class ContainerWithExtensionIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() - .id("extension-1") - .name("my-extension") - .version("1.0") - .mainClass(MyExtension.class).build(); + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtension.class).build(); final HiveMQContainer extension = - new HiveMQContainer() - .waitForExtension(hiveMQExtension) - .withExtension(hiveMQExtension); + new HiveMQContainer() + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java index 08860931558..a81b5626378 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -28,6 +28,7 @@ import org.slf4j.event.Level; import org.testcontainers.hivemq.util.MyExtensionWithSubclasses; import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; import java.util.concurrent.TimeUnit; @@ -40,16 +41,17 @@ public class ContainerWithExtensionSubclassIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() - .id("extension-1") - .name("my-extension") - .version("1.0") - .mainClass(MyExtensionWithSubclasses.class).build(); + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtensionWithSubclasses.class).build(); final HiveMQContainer extension = - new HiveMQContainer() - .waitForExtension(hiveMQExtension) - .withExtension(hiveMQExtension) - .withLogLevel(Level.DEBUG); + new HiveMQContainer() + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension) + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withLogLevel(Level.DEBUG); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java index 359fda2ad86..339790b8a90 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -59,6 +59,7 @@ void test() throws Exception { final HiveMQContainer extension = new HiveMQContainer() + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .withExtension(hiveMQExtension) .waitForExtension(hiveMQExtension) .withFileInExtensionHomeFolder( diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java index d622e81ad8f..ee520ed4b36 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -51,17 +51,18 @@ public class ContainerWithFileInHomeIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() - .id("extension-1") - .name("my-extension") - .version("1.0") - .mainClass(FileCheckerExtension.class).build(); + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCheckerExtension.class).build(); final HiveMQContainer extension = - new HiveMQContainer() - .withExtension(hiveMQExtension) - .waitForExtension(hiveMQExtension) - .withFileInHomeFolder(MountableFile.forClasspathResource("/additionalFile.txt"), - "/additionalFiles/my-file.txt"); + new HiveMQContainer() + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withFileInHomeFolder(MountableFile.forClasspathResource("/additionalFile.txt"), + "/additionalFiles/my-file.txt"); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java index b4d642308a3..cd3c24ccc64 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java @@ -40,12 +40,13 @@ public class ContainerWithGradleExtensionIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) public void test() throws Exception { final MountableFile gradleExtension = new GradleHiveMQExtensionSupplier( - new File(getClass().getResource("/gradle-extension").toURI())) - .get(); + new File(getClass().getResource("/gradle-extension").toURI())) + .get(); final HiveMQContainer container = new HiveMQContainer() - .waitForExtension("Gradle Extension") - .withExtension(gradleExtension); + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension("Gradle Extension") + .withExtension(gradleExtension); container.start(); TestPublishModifiedUtil.testPublishModified(container.getMqttPort()); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java index c1dc243a060..1768282719c 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -51,17 +51,18 @@ public class ContainerWithLicenseIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() - .id("extension-1") - .name("my-extension") - .version("1.0") - .mainClass(LicenceCheckerExtension.class).build(); + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(LicenceCheckerExtension.class).build(); final HiveMQContainer extension = - new HiveMQContainer() - .withExtension(hiveMQExtension) - .waitForExtension(hiveMQExtension) - .withLicense(MountableFile.forClasspathResource("/myLicense.lic")) - .withLicense(MountableFile.forClasspathResource("/myExtensionLicense.elic")); + new HiveMQContainer() + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension) + .withLicense(MountableFile.forClasspathResource("/myLicense.lic")) + .withLicense(MountableFile.forClasspathResource("/myExtensionLicense.elic")); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java index d8f1df1ac4e..e90cfb257ba 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java @@ -39,15 +39,16 @@ public class ContainerWithMavenExtensionIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final MountableFile mavenExtension = new MavenHiveMQExtensionSupplier( - getClass().getResource("/maven-extension/pom.xml").getPath()) - .addProperty("HIVEMQ_GROUP_ID", "com.hivemq") - .addProperty("HIVEMQ_EXTENSION_SDK", "hivemq-extension-sdk") - .addProperty("HIVEMQ_EXTENSION_SDK_VERSION", "4.3.0") - .get(); + getClass().getResource("/maven-extension/pom.xml").getPath()) + .addProperty("HIVEMQ_GROUP_ID", "com.hivemq") + .addProperty("HIVEMQ_EXTENSION_SDK", "hivemq-extension-sdk") + .addProperty("HIVEMQ_EXTENSION_SDK_VERSION", "4.3.0") + .get(); final HiveMQContainer extension = new HiveMQContainer() - .waitForExtension("Maven Extension") - .withExtension(mavenExtension); + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension("Maven Extension") + .withExtension(mavenExtension); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java index 09142f68e8e..c530a1be6a9 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -63,13 +63,14 @@ public class CreateFileInCopiedDirectoryIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() - .id("extension-1") - .name("my-extension") - .version("1.0") - .mainClass(FileCreatorExtension.class).build(); + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCreatorExtension.class).build(); final HiveMQContainer extension = new HiveMQContainer() + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .withExtension(hiveMQExtension) .waitForExtension(hiveMQExtension) .withFileInHomeFolder(createDirectory(), "directory"); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java index d4fea3b3185..3750380f947 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -35,6 +35,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.testcontainers.hivemq.util.TestPublishModifiedUtil; +import org.testcontainers.utility.MountableFile; import java.io.File; import java.io.IOException; @@ -51,15 +52,16 @@ public class CreateFileInExtensionDirectoryIT { @Timeout(value = 3, unit = TimeUnit.MINUTES) void test() throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() - .id("extension-1") - .name("my-extension") - .version("1.0") - .mainClass(FileCreatorExtension.class).build(); + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(FileCreatorExtension.class).build(); final HiveMQContainer extension = - new HiveMQContainer() - .waitForExtension(hiveMQExtension) - .withExtension(hiveMQExtension); + new HiveMQContainer() + .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) + .waitForExtension(hiveMQExtension) + .withExtension(hiveMQExtension); extension.start(); TestPublishModifiedUtil.testPublishModified(extension.getMqttPort()); extension.stop(); diff --git a/modules/hivemq/src/test/resources/inMemoryConfig.xml b/modules/hivemq/src/test/resources/inMemoryConfig.xml new file mode 100644 index 00000000000..33373359243 --- /dev/null +++ b/modules/hivemq/src/test/resources/inMemoryConfig.xml @@ -0,0 +1,6 @@ + + + + in-memory + + From 6439592973e2da26872b41bca15ed42678b6ba26 Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 29 Nov 2021 13:29:42 +0100 Subject: [PATCH 09/30] updated license header --- .../src/test/resources/inMemoryConfig.xml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/modules/hivemq/src/test/resources/inMemoryConfig.xml b/modules/hivemq/src/test/resources/inMemoryConfig.xml index 33373359243..7198f298401 100644 --- a/modules/hivemq/src/test/resources/inMemoryConfig.xml +++ b/modules/hivemq/src/test/resources/inMemoryConfig.xml @@ -1,4 +1,29 @@ + in-memory From 597f246232b3a456d0a2a884688fef22ac51c78f Mon Sep 17 00:00:00 2001 From: codepitbull Date: Wed, 15 Dec 2021 10:18:17 +0100 Subject: [PATCH 10/30] First iteration of public docs --- docs/modules/hviemq.md | 354 ++++++++++++++++++ .../hivemq/ContainerWithControlCenterIT.java | 1 - 2 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 docs/modules/hviemq.md diff --git a/docs/modules/hviemq.md b/docs/modules/hviemq.md new file mode 100644 index 00000000000..b393a6a3b46 --- /dev/null +++ b/docs/modules/hviemq.md @@ -0,0 +1,354 @@ +# RabbitMQ Module + +# HiveMQ Test Container + +![image](https://www.hivemq.com/img/logo-hivemq-testcontainer.png) + +Automatic starting HiveMQ docker containers for JUnit4 and JUnit5 tests. +This enables testing MQTT client applications and integration testing of custom HiveMQ extensions. + +- Community forum: https://community.hivemq.com/ +- HiveMQ website: https://www.hivemq.com/ +- MQTT resources: + - [MQTT Essentials](https://www.hivemq.com/mqtt-essentials/) + - [MQTT 5 Essentials](https://www.hivemq.com/mqtt-5/) + +## Add to your project + +### Gradle + +Add to `build.gradle`: + +````groovy +testImplementation 'org.testcontainers:hivemq:{{latest_version}}' +```` + +Add to `build.gradle.kts`: + +````kotlin +testImplementation("org.testcontainers:hivemq:{{latest_version}}") +```` + +### Maven + +Add to `pom.xml`: + +```xml + + com.hivemq + hivemq + {{latest_version}} + test + +``` + + +## User defined HiveMQ image and tag + +The default image is the 'hivemq/hivemq-ce' using the '2021.3'. +As always, the constructor allows to specify a custom image and tag, details on the available tags for community edition +are available in our [Docker-repository](https://hub.docker.com/r/hivemq/hivemq-ce). + +You can alos pick the HiveMQ-enterprise edition using the image name 'hivemq/hivemq4'. Please check the [Docker-repository](https://hub.docker.com/r/hivemq/hivemq4) + for available tags. + +An example for explicitly specifiying image and version. +```java +import org.testcontainers.hivemq.HiveMQContainer + +@Container +final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq-ce:2021.3"); +``` + +## Test your MQTT 3 and MQTT 5 client application + +Using an Mqtt-client (e.g. the [HiveMQ-Open-Source-Client](https://github.com/hivemq/hivemq-mqtt-client)) you can start +testing directly. + +```java +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; + +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + +@Test +public void test_mqtt() { + + final Mqtt5BlockingClient client = Mqtt5Client.builder() + .serverPort(hivemq.getMqttPort()) + .buildBlocking(); + + client.connect(); + client.disconnect(); +} +``` + +## Set logging level + +The logging level of the HiveMQ testcontainer can be controlled using the withLogLevel-methid on the builder. + +--- +**Note:** you can silence the container at any time using the `.silent(true)` method. + +--- + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withLogLevel(Level.DEBUG); +``` + +## Set Control Center Port + +The HiveMQ Testcontainer can make the HiveMQ Control Center available. + +--- +**Note:** that the HiveMQ Control Center is a feature of the HiveMQ Enterprise Edition. + +--- + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withControlCenter(); +``` + +After startup, you are presented with the URL of the HiveMQ Control Center: + +``` +2021-09-10 10:35:53,511 INFO - The HiveMQ Control Center is reachable under: http://localhost:55032 +``` + +## Add a custom HiveMQ configuration + +In situations where additional configuration is required the file can be specified using the provided builder. +The contents of *config.xml* are documented [here](https://github.com/hivemq/hivemq-community-edition/wiki/Configuration). + +```java +@RegisterExtension +final HiveMQContainer hivemq = new HiveMQContainer() + .withHiveMQConfig(new File("src/test/resources/config.xml")); +``` + +## Testing HiveMQ extensions + +Using the [Extension SDK](https://github.com/hivemq/hivemq-extension-sdk) the functionality of all editions of HiveMQ +can be extended. +The HiveMQ-testcontainer also supports testing these custom extensions of yours. + +### Wait Strategy + +The raw HiveMQ-testcontainer is built to wait for certain startup log messages to signal readiness. +Since extensions are loaded dynamically they will 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: +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withExtension(new File("src/test/resources/modifier-extension")) + .waitForExtension("My Extension Name"); +``` + +Next up we have an example for using an extension directly from the classpath: +```java +final HiveMQExtension hiveMQExtension = HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtension.class).build(); + +@Container +final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq4", "latest") + .withExtension(hiveMQExtension) + .waitForExtension(hiveMQExtension); +``` + +### Testing extensions using Gradle + +In a Gradle based HiveMQ Extension project we support testing using a dedicated [HiveMQ Extension Gradle Plugin](https://github.com/hivemq/hivemq-extension-gradle-plugin/edit/master/README.md). + +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: +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq4", "latest") + .withExtension(new File("build/hivemq-extension-test/")); +``` + +### Remote debugging of loaded extensions + +You can debug extensions that are directly loaded from your code: + +- put a break point in your extension +- enable remote debugging on your container + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withDebugging(); +``` + +#### Load an extension from a Gradle project + +It is also possible to reference an extension in a different Gradle project by using the **GradleHiveMQExtensionSupplier**: + +```java +import org.testcontainers.hivemq.GradleHiveMQExtensionSupplier; + +@Container +final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq4", "latest") + .withExtension(new GradleHiveMQExtensionSupplier(new File("path/to/extension/")).get()); +``` + +### Testing extensions using Maven + +You can package and load an extension from a separate maven project by referencing the **pom.xml** of said project: +```java +import org.testcontainers.hivemq.MavenHiveMQExtensionSupplier; + +@Container +final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq4", "latest") + .withExtension(new MavenHiveMQExtensionSupplier("path/to/extension/pom.xml").get()); +``` + +### 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. + +--- + +```java +private final @NotNull 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("hivemq/hivemq4", "latest") + .withExtension(hiveMQExtension); + +@Test +void test_disable_enable_extension() throws ExecutionException, InterruptedException { + hivemq.enableExtension(hiveMQExtension); + hivemq.disableExtension(hiveMQExtension); +} +``` + +## Enable/Disable an extension loaded from a folder + +You can enable or disable extensions loaded from an extension folder during runtime. +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. + +--- + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq4", "latest") + .withExtension(new File("src/test/resources/modifier-extension")); + +@Test +void test_disable_enable_extension() throws ExecutionException, InterruptedException { + hivemq.disableExtension("Modifier Extension", "modifier-extension"); + hivemq.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. + +### Remove all prepackaged extensions: + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withoutPrepackagedExtensions(); +``` + +### Remove specific prepackaged extensions: + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withoutPrepackagedExtensions("hivemq-kafka-extension"); +``` + +## Put files into the container + +### Put a file into HiveMQ home + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withFileInHomeFolder( + new File("src/test/resources/additionalFile.txt"), + "/path/in/home/folder"); +``` + +### Put files into extension home + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withExtension(HiveMQExtension.builder() + .id("extension-1") + .name("my-extension") + .version("1.0") + .mainClass(MyExtension.class).build()) + .withFileInExtensionHomeFolder( + new File("src/test/resources/additionalFile.txt"), + "extension-1", + "/path/in/extension/home"); +``` + +### Put license files into the container + +```java +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withLicense(new File("src/test/resources/myLicense.lic")) + .withLicense(new File("src/test/resources/myExtensionLicense.elic")); +``` + +### Configure Docker resources + +```java +@RegisterExtension +@Container +final HiveMQContainer hivemq = new HiveMQContainer() + .withCreateContainerCmdModifier(createContainerCmd -> { + final HostConfig hostConfig = HostConfig.newHostConfig(); + hostConfig.withCpuCount(2L); + hostConfig.withMemory(2 * 1024 * 1024L); + }); +``` + +### Customize the Container further + +Since the `HiveMQContainer` extends from [Testcontainer's](https://github.com/testcontainers) `GenericContainer` the container +can be customized as desired. + +## Contributing + +If you want to contribute to the HiveMQ Testcontainer, see the [contribution guidelines](CONTRIBUTING.md). + +## License + +The HiveMQ Testcontainer is licensed under the `APACHE LICENSE, VERSION 2.0`. A copy of the license can be found [here](LICENSE). diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java index 7d608717103..c20ad6f8f90 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -29,7 +29,6 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; -import org.testcontainers.utility.DockerImageName; import java.util.concurrent.TimeUnit; From 883f213b2819d6b08d6f451d39cf2059a10a3bf7 Mon Sep 17 00:00:00 2001 From: Jochen Mader Date: Wed, 15 Dec 2021 15:01:16 +0100 Subject: [PATCH 11/30] Fix groupId Co-authored-by: Yannick Weber --- docs/modules/hviemq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/hviemq.md b/docs/modules/hviemq.md index b393a6a3b46..f3d1d990c14 100644 --- a/docs/modules/hviemq.md +++ b/docs/modules/hviemq.md @@ -35,7 +35,7 @@ Add to `pom.xml`: ```xml - com.hivemq + org.testcontainers hivemq {{latest_version}} test From d3c637968a947e3eb8968a56a878ec098d04e198 Mon Sep 17 00:00:00 2001 From: Jochen Mader Date: Wed, 15 Dec 2021 15:08:05 +0100 Subject: [PATCH 12/30] Apply suggestions from code review Co-authored-by: Yannick Weber --- docs/modules/hviemq.md | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/modules/hviemq.md b/docs/modules/hviemq.md index f3d1d990c14..1662342014c 100644 --- a/docs/modules/hviemq.md +++ b/docs/modules/hviemq.md @@ -45,7 +45,7 @@ Add to `pom.xml`: ## User defined HiveMQ image and tag -The default image is the 'hivemq/hivemq-ce' using the '2021.3'. +The default image is the 'hivemq/hivemq-ce' using the '2021.3' version. As always, the constructor allows to specify a custom image and tag, details on the available tags for community edition are available in our [Docker-repository](https://hub.docker.com/r/hivemq/hivemq-ce). @@ -56,19 +56,24 @@ An example for explicitly specifiying image and version. ```java import org.testcontainers.hivemq.HiveMQContainer -@Container -final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq-ce:2021.3"); -``` +public class MqttTest { + + @Container + final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq-ce:2021.3"); + +} ## Test your MQTT 3 and MQTT 5 client application -Using an Mqtt-client (e.g. the [HiveMQ-Open-Source-Client](https://github.com/hivemq/hivemq-mqtt-client)) you can start +Using an Mqtt-client (e.g. the [HiveMQ-Mqtt-Client](https://github.com/hivemq/hivemq-mqtt-client)) you can start testing directly. ```java import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +public class MqttTest { + @Container final HiveMQContainer hivemq = new HiveMQContainer() @@ -82,6 +87,7 @@ public void test_mqtt() { client.connect(); client.disconnect(); } +} ``` ## Set logging level @@ -99,7 +105,7 @@ final HiveMQContainer hivemq = new HiveMQContainer() .withLogLevel(Level.DEBUG); ``` -## Set Control Center Port +## HiveMQ Control Center The HiveMQ Testcontainer can make the HiveMQ Control Center available. @@ -128,7 +134,7 @@ The contents of *config.xml* are documented [here](https://github.com/hivemq/hiv ```java @RegisterExtension final HiveMQContainer hivemq = new HiveMQContainer() - .withHiveMQConfig(new File("src/test/resources/config.xml")); + .withHiveMQConfig(MountableFile.forHostPath("/path/to/config.xml")); ``` ## Testing HiveMQ extensions @@ -140,7 +146,7 @@ The HiveMQ-testcontainer also supports testing these custom extensions of yours. ### Wait Strategy The raw HiveMQ-testcontainer is built to wait for certain startup log messages to signal readiness. -Since extensions are loaded dynamically they will be available a short while after the main container has started. +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 @@ -148,7 +154,7 @@ wait for an extension named **'My Extension Name'** to be started: ```java @Container final HiveMQContainer hivemq = new HiveMQContainer() - .withExtension(new File("src/test/resources/modifier-extension")) + .withExtension(MountableFile.forHostPath("src/test/resources/modifier-extension")) .waitForExtension("My Extension Name"); ``` @@ -259,7 +265,7 @@ If the extension folder contains a DISABLED file, the extension will be disabled ```java @Container final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq4", "latest") - .withExtension(new File("src/test/resources/modifier-extension")); + .withExtension(new MountableFile.forHostPath("src/test/resources/modifier-extension")); @Test void test_disable_enable_extension() throws ExecutionException, InterruptedException { @@ -298,7 +304,7 @@ final HiveMQContainer hivemq = new HiveMQContainer() @Container final HiveMQContainer hivemq = new HiveMQContainer() .withFileInHomeFolder( - new File("src/test/resources/additionalFile.txt"), + MountableFile.forHostPath("src/test/resources/additionalFile.txt"), "/path/in/home/folder"); ``` @@ -313,7 +319,7 @@ final HiveMQContainer hivemq = new HiveMQContainer() .version("1.0") .mainClass(MyExtension.class).build()) .withFileInExtensionHomeFolder( - new File("src/test/resources/additionalFile.txt"), + MountableFile.forHostPath("src/test/resources/additionalFile.txt"), "extension-1", "/path/in/extension/home"); ``` From 5b42a93c09197213be1666e8d0b0d854fe9d7de0 Mon Sep 17 00:00:00 2001 From: Jochen Mader Date: Wed, 15 Dec 2021 15:08:40 +0100 Subject: [PATCH 13/30] Removed leftover license info --- docs/modules/hviemq.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/modules/hviemq.md b/docs/modules/hviemq.md index 1662342014c..d6769b14422 100644 --- a/docs/modules/hviemq.md +++ b/docs/modules/hviemq.md @@ -354,7 +354,3 @@ can be customized as desired. ## Contributing If you want to contribute to the HiveMQ Testcontainer, see the [contribution guidelines](CONTRIBUTING.md). - -## License - -The HiveMQ Testcontainer is licensed under the `APACHE LICENSE, VERSION 2.0`. A copy of the license can be found [here](LICENSE). From 4b463eff5885a9ee15c5deb916d9a132f5c71b0e Mon Sep 17 00:00:00 2001 From: Jochen Mader Date: Wed, 15 Dec 2021 15:10:29 +0100 Subject: [PATCH 14/30] Update docs/modules/hviemq.md Co-authored-by: Yannick Weber --- docs/modules/hviemq.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/modules/hviemq.md b/docs/modules/hviemq.md index d6769b14422..8c80831c1c8 100644 --- a/docs/modules/hviemq.md +++ b/docs/modules/hviemq.md @@ -234,6 +234,7 @@ It is possible to enable and disable HiveMQ extensions during runtime. Extension --- ```java +public class MqttTest { private final @NotNull HiveMQExtension hiveMQExtension = HiveMQExtension.builder() .id("extension-1") .name("my-extension") @@ -250,6 +251,7 @@ void test_disable_enable_extension() throws ExecutionException, InterruptedExcep hivemq.enableExtension(hiveMQExtension); hivemq.disableExtension(hiveMQExtension); } +} ``` ## Enable/Disable an extension loaded from a folder From e4b0b1286f993029d0bb1cfc953aa6cce1c7f5b7 Mon Sep 17 00:00:00 2001 From: Jochen Mader Date: Wed, 15 Dec 2021 16:36:44 +0100 Subject: [PATCH 15/30] Working recommendations in --- docs/modules/hviemq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/hviemq.md b/docs/modules/hviemq.md index 8c80831c1c8..0d901f8a6b8 100644 --- a/docs/modules/hviemq.md +++ b/docs/modules/hviemq.md @@ -59,7 +59,7 @@ import org.testcontainers.hivemq.HiveMQContainer public class MqttTest { @Container - final HiveMQContainer hivemq = new HiveMQContainer("hivemq/hivemq-ce:2021.3"); + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce:2021.3")); } From 676dd2375803d90b7df4bdcd3d7f5b634c91c3de Mon Sep 17 00:00:00 2001 From: yannick Date: Tue, 21 Dec 2021 15:01:12 +0100 Subject: [PATCH 16/30] renamed hviemq to hivemq RabbitMQ -> HiveMQ --- docs/modules/{hviemq.md => hivemq.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename docs/modules/{hviemq.md => hivemq.md} (99%) diff --git a/docs/modules/hviemq.md b/docs/modules/hivemq.md similarity index 99% rename from docs/modules/hviemq.md rename to docs/modules/hivemq.md index 0d901f8a6b8..eb4b016190f 100644 --- a/docs/modules/hviemq.md +++ b/docs/modules/hivemq.md @@ -1,4 +1,4 @@ -# RabbitMQ Module +# HiveMQ Module # HiveMQ Test Container From cb40119dd6266dfeee55eef6dc66069e095fc66e Mon Sep 17 00:00:00 2001 From: yannick Date: Wed, 22 Dec 2021 13:51:10 +0100 Subject: [PATCH 17/30] removed hivemq-extension-sdk compile-dependency added java-doc to HiveMQExtension added additional check to HiveMQExtension configured gradle to execute tests with Java 11 --- modules/hivemq/build.gradle.kts | 8 +- modules/hivemq/gradle.properties | 3 +- .../hivemq/HiveMQContainer.java | 4 +- .../hivemq/HiveMQExtension.java | 111 ++++++++++++++---- .../hivemq/HiveMQExtensionTest.java | 16 +++ 5 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index 1bedde845e9..4f7014cfb25 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -28,8 +28,6 @@ dependencies { exclude("org.codehouse.plexus", "plexus-utils") } - compileOnly("com.hivemq:hivemq-extension-sdk:${property("hivemq-extension-sdk.version")}") - testImplementation("org.junit.jupiter:junit-jupiter-api:${property("junit5.version")}") testImplementation("com.hivemq:hivemq-extension-sdk:${property("hivemq-extension-sdk.version")}") testImplementation("com.hivemq:hivemq-mqtt-client:${property("hivemq-mqtt-client.version")}") @@ -42,6 +40,12 @@ tasks.withType { useJUnitPlatform() } +tasks.named("compileTestJava") { + javaCompiler.set(javaToolchains.compilerFor { + languageVersion.set(JavaLanguageVersion.of(11)) + }) +} + license { header = projectDir.resolve("HEADER") mapping("java", "SLASHSTAR_STYLE") diff --git a/modules/hivemq/gradle.properties b/modules/hivemq/gradle.properties index 9ddbe187464..08d70a44e6b 100644 --- a/modules/hivemq/gradle.properties +++ b/modules/hivemq/gradle.properties @@ -2,8 +2,7 @@ version=2.0.0 # # main dependencies # -testcontainers.version=1.16.0 -hivemq-extension-sdk.version=4.4.4 +hivemq-extension-sdk.version=4.7.3 junit4.version=4.13.2 annotations.version=22.0.0 commons-lang.version=3.12.0 diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index f20ed843cd8..f7592148693 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -23,7 +23,6 @@ */ package org.testcontainers.hivemq; -import com.hivemq.extension.sdk.api.ExtensionMain; import javassist.ClassPool; import javassist.NotFoundException; import org.apache.commons.io.FileUtils; @@ -83,6 +82,7 @@ public class HiveMQContainer extends GenericContainer { @SuppressWarnings("OctalInteger") private static final int MODE = 0777; private static final @NotNull Pattern EXTENSION_ID_PATTERN = Pattern.compile("(.+?)"); + public static final @NotNull String EXTENSION_MAIN_CLASS_NAME = "com.hivemq.extension.sdk.api.ExtensionMain"; private final @NotNull ConcurrentHashMap containerOutputLatches = new ConcurrentHashMap<>(); private volatile boolean silent = false; @@ -272,7 +272,7 @@ public void start() { final JavaArchive javaArchive = ShrinkWrap.create(JavaArchive.class) - .addAsServiceProviderAndClasses(ExtensionMain.class, hiveMQExtension.getMainClass()); + .addAsServiceProvider(EXTENSION_MAIN_CLASS_NAME, hiveMQExtension.getMainClass().getName()); putSubclassesIntoJar(hiveMQExtension.getId(), hiveMQExtension.getMainClass(), javaArchive); for (final Class additionalClass : hiveMQExtension.getAdditionalClasses()) { diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java index 5dfa79c7187..c842199562f 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -24,7 +24,6 @@ package org.testcontainers.hivemq; import com.google.common.collect.ImmutableList; -import com.hivemq.extension.sdk.api.ExtensionMain; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,18 +38,18 @@ public class HiveMQExtension { private final int priority; private final int startPriority; private final boolean disabledOnStartup; - private final @NotNull Class mainClass; + private final @NotNull Class mainClass; private final @NotNull ImmutableList> additionalClasses; private HiveMQExtension( - final @NotNull String id, - final @NotNull String name, - final @NotNull String version, - final int priority, - final int startPriority, - final boolean disabledOnStartup, - final @NotNull Class mainClass, - final @NotNull ImmutableList> additionalClasses) { + final @NotNull String id, + final @NotNull String name, + final @NotNull String version, + final int priority, + final int startPriority, + final boolean disabledOnStartup, + final @NotNull Class mainClass, + final @NotNull ImmutableList> additionalClasses) { this.id = id; this.name = name; @@ -86,7 +85,7 @@ public boolean isDisabledOnStartup() { return disabledOnStartup; } - public @NotNull Class getMainClass() { + public @NotNull Class getMainClass() { return mainClass; } @@ -105,10 +104,14 @@ public static final class Builder { private int priority = 0; private int startPriority = 0; private boolean disabledOnStartup = false; - private @Nullable Class mainClass; + private @Nullable Class mainClass; private final @NotNull ImmutableList.Builder> additionalClassesBuilder = ImmutableList.builder(); - public HiveMQExtension build() { + /** + * Builds the {@link HiveMQExtension} with the provided values or default values. + * @return the HiveMQ Extension + */ + public @NotNull HiveMQExtension build() { if (id == null || id.isEmpty()) { throw new IllegalArgumentException("extension id must not be null or empty"); } @@ -122,52 +125,112 @@ public HiveMQExtension build() { throw new IllegalArgumentException("extension main class must not be null"); } return new HiveMQExtension( - id, - name, - version, - priority, - startPriority, - disabledOnStartup, - mainClass, - additionalClassesBuilder.build() + id, + name, + version, + priority, + startPriority, + disabledOnStartup, + mainClass, + additionalClassesBuilder.build() ); } + /** + * Sets the identifier of the {@link HiveMQExtension}. + * + * @param id the identifier, must not be empty + * @return the {@link Builder} + */ public @NotNull Builder id(final @NotNull String id) { this.id = id; return this; } + /** + * Sets the name of the {@link HiveMQExtension}. + * + * @param name the identifier, must not be empty + * @return the {@link Builder} + */ public @NotNull Builder name(final @NotNull String name) { this.name = name; return this; } + /** + * Sets the version of the {@link HiveMQExtension}. + * + * @param version the version, must not be empty + * @return the {@link Builder} + */ public @NotNull Builder version(final @NotNull String version) { this.version = version; return this; } + /** + * Sets the priority of the {@link HiveMQExtension}. + * + * @param priority the priority + * @return the {@link Builder} + */ public @NotNull Builder priority(final int priority) { this.priority = priority; return this; } + /** + * Sets the start-priority of the {@link HiveMQExtension}. + * + * @param startPriority the start-priority + * @return the {@link Builder} + */ public @NotNull Builder startPriority(final int startPriority) { this.startPriority = startPriority; return this; } + /** + * Flag, that indicates whether the {@link HiveMQExtension} should be disabled when HiveMQ starts. + * Disabling on startup is achieved by placing a DISABLED file in the {@link HiveMQExtension}'s directory before coping it to the container. + * + * @param disabledOnStartup if the {@link HiveMQExtension} should be disabled when HiveMQ starts + * @return the {@link Builder} + */ public @NotNull Builder disabledOnStartup(final boolean disabledOnStartup) { this.disabledOnStartup = disabledOnStartup; return this; } - public @NotNull Builder mainClass(final @NotNull Class mainClass) { - this.mainClass = mainClass; - return this; + /** + * The main class of the {@link HiveMQExtension}. + * This class MUST implement {@link com.hivemq.extension.sdk.api.ExtensionMain}. + * + * @param mainClass the main class + * @return the {@link Builder} + * @throws IllegalArgumentException if the provides class does not implement {@link com.hivemq.extension.sdk.api.ExtensionMain} + * @throws IllegalStateException if {@link com.hivemq.extension.sdk.api.ExtensionMain} is not found in the classpath + */ + public @NotNull Builder mainClass(final @NotNull Class mainClass) { + try { + final Class extensionMain = Class.forName(HiveMQContainer.EXTENSION_MAIN_CLASS_NAME); + if (!extensionMain.isAssignableFrom(mainClass)) { + throw new IllegalArgumentException("The provided class does not implement '" + HiveMQContainer.EXTENSION_MAIN_CLASS_NAME + "'"); + } + this.mainClass = mainClass; + return this; + } catch (final ClassNotFoundException e) { + throw new IllegalStateException("The class '" + HiveMQContainer.EXTENSION_MAIN_CLASS_NAME + "' was not found in the classpath."); + } } + /** + * Adds an additional class to the .jar file of the {@link HiveMQExtension}. + * + * @param clazz the additional class + * @return the {@link Builder} + */ public @NotNull Builder addAdditionalClass(final @NotNull Class clazz) { this.additionalClassesBuilder.add(clazz); return this; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java new file mode 100644 index 00000000000..f260da78fe1 --- /dev/null +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQExtensionTest.java @@ -0,0 +1,16 @@ +package org.testcontainers.hivemq; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Yannick Weber + */ +class HiveMQExtensionTest { + + @Test + void builder_classDoesNotImplementExtensionMain_exception() { + assertThrows(IllegalArgumentException.class, () -> HiveMQExtension.builder().mainClass(HiveMQExtensionTest.class)); + } +} From c630b2bec02732ea12f440572024aa9fdb95eb57 Mon Sep 17 00:00:00 2001 From: yannick Date: Wed, 22 Dec 2021 15:25:07 +0100 Subject: [PATCH 18/30] removed license headers --- modules/hivemq/HEADER | 21 ---------------- modules/hivemq/build.gradle.kts | 7 ------ .../hivemq/GradleHiveMQExtensionSupplier.java | 23 ----------------- .../hivemq/HiveMQContainer.java | 23 ----------------- .../hivemq/HiveMQExtension.java | 23 ----------------- .../hivemq/MavenHiveMQExtensionSupplier.java | 23 ----------------- .../hivemq/MultiLogMessageWaitStrategy.java | 23 ----------------- .../org/testcontainers/hivemq/PathUtil.java | 23 ----------------- .../hivemq/ContainerWithControlCenterIT.java | 23 ----------------- .../hivemq/ContainerWithCustomConfigIT.java | 23 ----------------- ...ContainerWithExtensionFromDirectoryIT.java | 23 ----------------- .../hivemq/ContainerWithExtensionIT.java | 23 ----------------- .../ContainerWithExtensionSubclassIT.java | 23 ----------------- .../ContainerWithFileInExtensionHomeIT.java | 23 ----------------- .../hivemq/ContainerWithFileInHomeIT.java | 23 ----------------- .../ContainerWithGradleExtensionIT.java | 23 ----------------- .../hivemq/ContainerWithLicenseIT.java | 23 ----------------- .../hivemq/ContainerWithMavenExtensionIT.java | 23 ----------------- .../ContainerWithoutPlatformExtensionsIT.java | 23 ----------------- .../hivemq/CreateFileInCopiedDirectoryIT.java | 23 ----------------- .../CreateFileInExtensionDirectoryIT.java | 23 ----------------- ...DisableEnableExtensionFromDirectoryIT.java | 23 ----------------- .../hivemq/DisableEnableExtensionIT.java | 23 ----------------- .../hivemq/DisableEnableMavenExtensionIT.java | 23 ----------------- .../hivemq/HiveMQTestContainerCore.java | 23 ----------------- .../testcontainers/hivemq/PathUtilTest.java | 23 ----------------- .../hivemq/util/MyExtension.java | 23 ----------------- .../util/MyExtensionWithSubclasses.java | 23 ----------------- .../hivemq/util/PublishModifier.java | 23 ----------------- .../hivemq/util/TestPublishModifiedUtil.java | 23 ----------------- .../src/test/resources/additionalFile.txt | 24 ------------------ modules/hivemq/src/test/resources/config.xml | 25 ------------------- .../resources/gradle-extension/build.gradle | 23 ----------------- .../gradle-extension/settings.gradle | 23 ----------------- .../src/main/java/com/hivemq/MyExtension.java | 23 ----------------- .../src/test/resources/inMemoryConfig.xml | 25 ------------------- .../src/test/resources/logback-test.xml | 25 ------------------- .../resources/maven-extension/assembly.xml | 25 ------------------- .../test/resources/maven-extension/pom.xml | 25 ------------------- .../src/main/java/com/hivemq/MyExtension.java | 23 ----------------- .../src/main/resources/hivemq-extension.xml | 25 ------------------- .../hivemq-extension.xml | 25 ------------------- .../modifier-extension/hivemq-extension.xml | 25 ------------------- 43 files changed, 988 deletions(-) delete mode 100644 modules/hivemq/HEADER diff --git a/modules/hivemq/HEADER b/modules/hivemq/HEADER deleted file mode 100644 index f016729ce96..00000000000 --- a/modules/hivemq/HEADER +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-present HiveMQ GmbH - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index 4f7014cfb25..85a82f44b5b 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -2,7 +2,6 @@ description = "Core API for testing MQTT Applications." plugins { `java-library` - id("com.github.hierynomus.license") version "0.16.1" } dependencies { @@ -45,9 +44,3 @@ tasks.named("compileTestJava") { languageVersion.set(JavaLanguageVersion.of(11)) }) } - -license { - header = projectDir.resolve("HEADER") - mapping("java", "SLASHSTAR_STYLE") - excludes(mutableListOf("**/gradle-wrapper.properties", "**/gradlew", "**/gradlew.bat")) -} diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java index d34bd779d62..c4f8d0766fe 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/GradleHiveMQExtensionSupplier.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import net.lingala.zip4j.ZipFile; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index f7592148693..d7944c3737d 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import javassist.ClassPool; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java index c842199562f..ecedf4d9744 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.google.common.collect.ImmutableList; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java index 6508232a724..a7935f56eca 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MavenHiveMQExtensionSupplier.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import net.lingala.zip4j.ZipFile; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java index 186f51b026f..316e2f2ac00 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/MultiLogMessageWaitStrategy.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.jetbrains.annotations.NotNull; diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java index 3dfe7973a83..59fd673718f 100755 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/PathUtil.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.jetbrains.annotations.NotNull; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java index c20ad6f8f90..0d89bc97223 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithControlCenterIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.apache.http.client.methods.HttpGet; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java index 8b002ae11a1..31dbf183c3b 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithCustomConfigIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.hivemq.client.mqtt.datatypes.MqttQos; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java index 07b80792795..ec102b24df9 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java index a36d85fdd28..adc7626c3c4 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java index a81b5626378..446c5423d19 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java index 339790b8a90..b4fe0dd47ee 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java index ee520ed4b36..dec44402883 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java index cd3c24ccc64..09feece35f1 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithGradleExtensionIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java index 1768282719c..cd1c31c01f8 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java index e90cfb257ba..438d53bf789 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithMavenExtensionIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java index 1a446939995..9bca8a35f4d 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithoutPlatformExtensionsIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.hivemq.client.mqtt.MqttClient; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java index c530a1be6a9..9a4419e43ef 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java index 3750380f947..3e7bbf8332e 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java index d1b060290af..d735b6b1534 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionFromDirectoryIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java index 69c0d811bc7..085c61cec8c 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableExtensionIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.jetbrains.annotations.NotNull; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java index c846893a531..5f2bf1dae31 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/DisableEnableMavenExtensionIT.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java index 2b520615ddf..ec8907fe149 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.jetbrains.annotations.NotNull; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java index d5d2cdb419d..04de999e68f 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/PathUtilTest.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq; import org.junit.jupiter.api.Test; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java index b3261bcb911..f2a4b443fd8 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtension.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq.util; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java index 33f2625b7b2..762e7cdcbc2 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/MyExtensionWithSubclasses.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq.util; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java index 2c2dfaaa147..229d3cfbdb3 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/PublishModifier.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq.util; import org.jetbrains.annotations.NotNull; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java index 209bf3dbbea..7cd4d0e0ae4 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/util/TestPublishModifiedUtil.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package org.testcontainers.hivemq.util; import com.hivemq.client.mqtt.MqttGlobalPublishFilter; diff --git a/modules/hivemq/src/test/resources/additionalFile.txt b/modules/hivemq/src/test/resources/additionalFile.txt index f59c5b3e6e8..e69de29bb2d 100755 --- a/modules/hivemq/src/test/resources/additionalFile.txt +++ b/modules/hivemq/src/test/resources/additionalFile.txt @@ -1,24 +0,0 @@ -==== - MIT License - - Copyright (c) 2021-present HiveMQ GmbH - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -==== - diff --git a/modules/hivemq/src/test/resources/config.xml b/modules/hivemq/src/test/resources/config.xml index e74cd80784e..128015e2fee 100755 --- a/modules/hivemq/src/test/resources/config.xml +++ b/modules/hivemq/src/test/resources/config.xml @@ -1,29 +1,4 @@ - diff --git a/modules/hivemq/src/test/resources/gradle-extension/build.gradle b/modules/hivemq/src/test/resources/gradle-extension/build.gradle index d698ead39fd..ed924772b4c 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/build.gradle +++ b/modules/hivemq/src/test/resources/gradle-extension/build.gradle @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ plugins { id 'java' id 'com.hivemq.extension' diff --git a/modules/hivemq/src/test/resources/gradle-extension/settings.gradle b/modules/hivemq/src/test/resources/gradle-extension/settings.gradle index 1cf9e116c10..dcfdbf138ea 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/settings.gradle +++ b/modules/hivemq/src/test/resources/gradle-extension/settings.gradle @@ -1,26 +1,3 @@ -/** - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ pluginManagement { plugins { id 'com.hivemq.extension' version '2.0.0' diff --git a/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java b/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java index be716fd408e..13231ffec20 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java +++ b/modules/hivemq/src/test/resources/gradle-extension/src/main/java/com/hivemq/MyExtension.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package com.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/resources/inMemoryConfig.xml b/modules/hivemq/src/test/resources/inMemoryConfig.xml index 7198f298401..33373359243 100644 --- a/modules/hivemq/src/test/resources/inMemoryConfig.xml +++ b/modules/hivemq/src/test/resources/inMemoryConfig.xml @@ -1,29 +1,4 @@ - in-memory diff --git a/modules/hivemq/src/test/resources/logback-test.xml b/modules/hivemq/src/test/resources/logback-test.xml index 88800b8f0e9..f992fc3be63 100644 --- a/modules/hivemq/src/test/resources/logback-test.xml +++ b/modules/hivemq/src/test/resources/logback-test.xml @@ -1,28 +1,3 @@ - diff --git a/modules/hivemq/src/test/resources/maven-extension/assembly.xml b/modules/hivemq/src/test/resources/maven-extension/assembly.xml index c252199af28..2be8dabfdfc 100644 --- a/modules/hivemq/src/test/resources/maven-extension/assembly.xml +++ b/modules/hivemq/src/test/resources/maven-extension/assembly.xml @@ -1,29 +1,4 @@ - distribution diff --git a/modules/hivemq/src/test/resources/maven-extension/pom.xml b/modules/hivemq/src/test/resources/maven-extension/pom.xml index dfe7751cfee..3c13b0d79c8 100644 --- a/modules/hivemq/src/test/resources/maven-extension/pom.xml +++ b/modules/hivemq/src/test/resources/maven-extension/pom.xml @@ -1,29 +1,4 @@ - 4.0.0 diff --git a/modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java b/modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java index be716fd408e..13231ffec20 100644 --- a/modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java +++ b/modules/hivemq/src/test/resources/maven-extension/src/main/java/com/hivemq/MyExtension.java @@ -1,26 +1,3 @@ -/* - * MIT License - * - * Copyright (c) 2021-present HiveMQ GmbH - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ package com.hivemq; import com.hivemq.extension.sdk.api.ExtensionMain; diff --git a/modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml b/modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml index 2284da43847..baf461e9011 100644 --- a/modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml +++ b/modules/hivemq/src/test/resources/maven-extension/src/main/resources/hivemq-extension.xml @@ -1,29 +1,4 @@ - ${artifactId} ${version} diff --git a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml index df55dfa9d82..6ca9c899df4 100755 --- a/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml +++ b/modules/hivemq/src/test/resources/modifier-extension-wrong-name/hivemq-extension.xml @@ -1,29 +1,4 @@ - modifier-extension 1.0-SNAPSHOT diff --git a/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml b/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml index df55dfa9d82..6ca9c899df4 100755 --- a/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml +++ b/modules/hivemq/src/test/resources/modifier-extension/hivemq-extension.xml @@ -1,29 +1,4 @@ - modifier-extension 1.0-SNAPSHOT From f0588e2e15af10c778808d5bee928cd9061848ff Mon Sep 17 00:00:00 2001 From: yannick Date: Thu, 23 Dec 2021 09:02:50 +0100 Subject: [PATCH 19/30] removed link in javadoc because ExtensionMain is not on the classpath during compilation --- .../java/org/testcontainers/hivemq/HiveMQExtension.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java index ecedf4d9744..c5c31f9c6ed 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -182,12 +182,12 @@ public static final class Builder { /** * The main class of the {@link HiveMQExtension}. - * This class MUST implement {@link com.hivemq.extension.sdk.api.ExtensionMain}. + * This class MUST implement com.hivemq.extension.sdk.api.ExtensionMain. * * @param mainClass the main class * @return the {@link Builder} - * @throws IllegalArgumentException if the provides class does not implement {@link com.hivemq.extension.sdk.api.ExtensionMain} - * @throws IllegalStateException if {@link com.hivemq.extension.sdk.api.ExtensionMain} is not found in the classpath + * @throws IllegalArgumentException if the provides class does not implement com.hivemq.extension.sdk.api.ExtensionMain} + * @throws IllegalStateException if com.hivemq.extension.sdk.api.ExtensionMain is not found in the classpath */ public @NotNull Builder mainClass(final @NotNull Class mainClass) { try { From 14f98a21f2089fc8e34959c8e04fe00b8189e3a4 Mon Sep 17 00:00:00 2001 From: yannick Date: Thu, 23 Dec 2021 09:15:34 +0100 Subject: [PATCH 20/30] removed guava dependency --- modules/hivemq/build.gradle.kts | 1 - modules/hivemq/gradle.properties | 1 - .../hivemq/HiveMQExtension.java | 19 +++++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index 85a82f44b5b..556ed3210e1 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -9,7 +9,6 @@ dependencies { api("org.jetbrains:annotations:${property("annotations.version")}") implementation("org.apache.commons:commons-lang3:${property("commons-lang.version")}") - implementation("com.google.guava:guava:${property("guava.version")}") implementation("commons-io:commons-io:${property("commons-io.version")}") implementation("org.javassist:javassist:${property("javassist.version")}") implementation("org.jboss.shrinkwrap:shrinkwrap-api:${property("shrinkwrap.version")}") diff --git a/modules/hivemq/gradle.properties b/modules/hivemq/gradle.properties index 08d70a44e6b..d69173a921a 100644 --- a/modules/hivemq/gradle.properties +++ b/modules/hivemq/gradle.properties @@ -7,7 +7,6 @@ junit4.version=4.13.2 annotations.version=22.0.0 commons-lang.version=3.12.0 commons-io.version=2.11.0 -guava.version=30.1.1-jre javassist.version=3.28.0-GA shrinkwrap.version=1.2.6 shrinkwrap-resolver.version=3.1.4 diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java index c5c31f9c6ed..e906c156bd5 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQExtension.java @@ -1,9 +1,12 @@ package org.testcontainers.hivemq; -import com.google.common.collect.ImmutableList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + /** * @author Yannick Weber */ @@ -16,7 +19,7 @@ public class HiveMQExtension { private final int startPriority; private final boolean disabledOnStartup; private final @NotNull Class mainClass; - private final @NotNull ImmutableList> additionalClasses; + private final @NotNull List> additionalClasses; private HiveMQExtension( final @NotNull String id, @@ -26,7 +29,7 @@ private HiveMQExtension( final int startPriority, final boolean disabledOnStartup, final @NotNull Class mainClass, - final @NotNull ImmutableList> additionalClasses) { + final @NotNull List> additionalClasses) { this.id = id; this.name = name; @@ -66,8 +69,8 @@ public boolean isDisabledOnStartup() { return mainClass; } - public @NotNull ImmutableList> getAdditionalClasses() { - return additionalClasses; + public @NotNull List> getAdditionalClasses() { + return Collections.unmodifiableList(additionalClasses); } public static @NotNull Builder builder() { @@ -82,7 +85,7 @@ public static final class Builder { private int startPriority = 0; private boolean disabledOnStartup = false; private @Nullable Class mainClass; - private final @NotNull ImmutableList.Builder> additionalClassesBuilder = ImmutableList.builder(); + private final @NotNull LinkedList> additionalClasses = new LinkedList<>(); /** * Builds the {@link HiveMQExtension} with the provided values or default values. @@ -109,7 +112,7 @@ public static final class Builder { startPriority, disabledOnStartup, mainClass, - additionalClassesBuilder.build() + additionalClasses ); } @@ -209,7 +212,7 @@ public static final class Builder { * @return the {@link Builder} */ public @NotNull Builder addAdditionalClass(final @NotNull Class clazz) { - this.additionalClassesBuilder.add(clazz); + this.additionalClasses.add(clazz); return this; } } From 69f57e573d62eb868b828f1ac7539ae2bfe9584a Mon Sep 17 00:00:00 2001 From: yannick Date: Thu, 23 Dec 2021 10:36:18 +0100 Subject: [PATCH 21/30] improved gradle.properties --- modules/hivemq/build.gradle.kts | 4 ++-- modules/hivemq/gradle.properties | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index 556ed3210e1..a05a0fc3870 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -1,4 +1,4 @@ -description = "Core API for testing MQTT Applications." +description = "TestContainers :: HiveMQ" plugins { `java-library` @@ -17,7 +17,7 @@ dependencies { /* This dependency needs to be explicitly added, because shrinkwrap-resolver-api-maven-embedded and shrinkwrap-resolver-impl-maven-embedded depend on different versions of it. - This would lead to issues when the HiveMQ Testcontainer is included in maven projects. */ + This would lead to issues when the HiveMQ container is included in maven projects. */ implementation("org.codehaus.plexus:plexus-utils:3.2.1") implementation("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-api-maven-embedded:${property("shrinkwrap-resolver.version")}") { exclude("org.codehouse.plexus", "plexus-utils") diff --git a/modules/hivemq/gradle.properties b/modules/hivemq/gradle.properties index d69173a921a..ef10f8bba20 100644 --- a/modules/hivemq/gradle.properties +++ b/modules/hivemq/gradle.properties @@ -1,10 +1,7 @@ -version=2.0.0 # # main dependencies # -hivemq-extension-sdk.version=4.7.3 -junit4.version=4.13.2 -annotations.version=22.0.0 +annotations.version=23.0.0 commons-lang.version=3.12.0 commons-io.version=2.11.0 javassist.version=3.28.0-GA @@ -14,7 +11,8 @@ zip4j.version=2.9.0 # # test dependencies # -hivemq-mqtt-client.version=1.2.2 +hivemq-extension-sdk.version=4.7.3 +hivemq-mqtt-client.version=1.3.0 httpclient.version=4.5.13 logback.version=1.2.3 junit5.version=5.8.1 From 2b587541a9581b9c1cdfce329c19cdca831c0b1f Mon Sep 17 00:00:00 2001 From: yannick Date: Thu, 23 Dec 2021 10:43:29 +0100 Subject: [PATCH 22/30] implementation -> shaded --- modules/hivemq/build.gradle.kts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index a05a0fc3870..7f5eaf3c818 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -8,18 +8,18 @@ dependencies { api(project(":testcontainers")) api("org.jetbrains:annotations:${property("annotations.version")}") - implementation("org.apache.commons:commons-lang3:${property("commons-lang.version")}") - implementation("commons-io:commons-io:${property("commons-io.version")}") - implementation("org.javassist:javassist:${property("javassist.version")}") - implementation("org.jboss.shrinkwrap:shrinkwrap-api:${property("shrinkwrap.version")}") - implementation("org.jboss.shrinkwrap:shrinkwrap-impl-base:${property("shrinkwrap.version")}") - implementation("net.lingala.zip4j:zip4j:${property("zip4j.version")}") + shaded("org.apache.commons:commons-lang3:${property("commons-lang.version")}") + shaded("commons-io:commons-io:${property("commons-io.version")}") + shaded("org.javassist:javassist:${property("javassist.version")}") + shaded("org.jboss.shrinkwrap:shrinkwrap-api:${property("shrinkwrap.version")}") + shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:${property("shrinkwrap.version")}") + shaded("net.lingala.zip4j:zip4j:${property("zip4j.version")}") /* This dependency needs to be explicitly added, because shrinkwrap-resolver-api-maven-embedded and shrinkwrap-resolver-impl-maven-embedded depend on different versions of it. This would lead to issues when the HiveMQ container is included in maven projects. */ - implementation("org.codehaus.plexus:plexus-utils:3.2.1") - implementation("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-api-maven-embedded:${property("shrinkwrap-resolver.version")}") { + shaded("org.codehaus.plexus:plexus-utils:3.2.1") + shaded("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-api-maven-embedded:${property("shrinkwrap-resolver.version")}") { exclude("org.codehouse.plexus", "plexus-utils") } runtimeOnly("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-impl-maven-embedded:${property("shrinkwrap-resolver.version")}") { From 5c6f7d2c0e890e6695b43073d66a5dcd06b499ac Mon Sep 17 00:00:00 2001 From: yannick Date: Wed, 5 Jan 2022 14:51:45 +0100 Subject: [PATCH 23/30] moved versions to build.gradle.kts --- modules/hivemq/build.gradle.kts | 28 ++++++++++++++-------------- modules/hivemq/gradle.properties | 18 ------------------ 2 files changed, 14 insertions(+), 32 deletions(-) delete mode 100644 modules/hivemq/gradle.properties diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle.kts index 7f5eaf3c818..787534d7148 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle.kts @@ -6,31 +6,31 @@ plugins { dependencies { api(project(":testcontainers")) - api("org.jetbrains:annotations:${property("annotations.version")}") + api("org.jetbrains:annotations:23.0.0") - shaded("org.apache.commons:commons-lang3:${property("commons-lang.version")}") - shaded("commons-io:commons-io:${property("commons-io.version")}") - shaded("org.javassist:javassist:${property("javassist.version")}") - shaded("org.jboss.shrinkwrap:shrinkwrap-api:${property("shrinkwrap.version")}") - shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:${property("shrinkwrap.version")}") - shaded("net.lingala.zip4j:zip4j:${property("zip4j.version")}") + shaded("org.apache.commons:commons-lang3:3.12.0") + shaded("commons-io:commons-io:2.11.0") + shaded("org.javassist:javassist:3.28.0-GA") + shaded("org.jboss.shrinkwrap:shrinkwrap-api:1.2.6") + shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") + shaded("net.lingala.zip4j:zip4j:2.9.0") /* This dependency needs to be explicitly added, because shrinkwrap-resolver-api-maven-embedded and shrinkwrap-resolver-impl-maven-embedded depend on different versions of it. This would lead to issues when the HiveMQ container is included in maven projects. */ shaded("org.codehaus.plexus:plexus-utils:3.2.1") - shaded("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-api-maven-embedded:${property("shrinkwrap-resolver.version")}") { + shaded("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-api-maven-embedded:3.1.4") { exclude("org.codehouse.plexus", "plexus-utils") } - runtimeOnly("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-impl-maven-embedded:${property("shrinkwrap-resolver.version")}") { + runtimeOnly("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-impl-maven-embedded:3.1.4") { exclude("org.codehouse.plexus", "plexus-utils") } - testImplementation("org.junit.jupiter:junit-jupiter-api:${property("junit5.version")}") - testImplementation("com.hivemq:hivemq-extension-sdk:${property("hivemq-extension-sdk.version")}") - testImplementation("com.hivemq:hivemq-mqtt-client:${property("hivemq-mqtt-client.version")}") - testImplementation("org.apache.httpcomponents:httpclient:${property("httpclient.version")}") - testImplementation("ch.qos.logback:logback-classic:${property("logback.version")}") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") + testImplementation("com.hivemq:hivemq-extension-sdk:4.7.3") + testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") + testImplementation("org.apache.httpcomponents:httpclient:4.5.13") + testImplementation("ch.qos.logback:logback-classic:1.2.3") } diff --git a/modules/hivemq/gradle.properties b/modules/hivemq/gradle.properties deleted file mode 100644 index ef10f8bba20..00000000000 --- a/modules/hivemq/gradle.properties +++ /dev/null @@ -1,18 +0,0 @@ -# -# main dependencies -# -annotations.version=23.0.0 -commons-lang.version=3.12.0 -commons-io.version=2.11.0 -javassist.version=3.28.0-GA -shrinkwrap.version=1.2.6 -shrinkwrap-resolver.version=3.1.4 -zip4j.version=2.9.0 -# -# test dependencies -# -hivemq-extension-sdk.version=4.7.3 -hivemq-mqtt-client.version=1.3.0 -httpclient.version=4.5.13 -logback.version=1.2.3 -junit5.version=5.8.1 From 2bad2691999cbfdb64d858f0c0051fbd417128e2 Mon Sep 17 00:00:00 2001 From: yannick Date: Wed, 5 Jan 2022 14:52:18 +0100 Subject: [PATCH 24/30] removed unnecessary header added hivemq to nav --- docs/modules/hivemq.md | 2 -- mkdocs.yml | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/modules/hivemq.md b/docs/modules/hivemq.md index eb4b016190f..8b177c9a07e 100644 --- a/docs/modules/hivemq.md +++ b/docs/modules/hivemq.md @@ -1,7 +1,5 @@ # HiveMQ Module -# HiveMQ Test Container - ![image](https://www.hivemq.com/img/logo-hivemq-testcontainer.png) Automatic starting HiveMQ docker containers for JUnit4 and JUnit5 tests. diff --git a/mkdocs.yml b/mkdocs.yml index be30f26a964..f3438c05995 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -65,6 +65,7 @@ nav: - modules/docker_compose.md - modules/elasticsearch.md - modules/gcloud.md + - modules/hivemq.md - modules/kafka.md - modules/localstack.md - modules/mockserver.md From 724bebd8dcbf290a941315ad8b2ee16c52a7a977 Mon Sep 17 00:00:00 2001 From: yannick Date: Mon, 10 Jan 2022 14:18:24 +0100 Subject: [PATCH 25/30] added new buildscript --- .../hivemq/{build.gradle.kts => build.gradle} | 20 ++++++++----------- .../{settings.gradle.kts => settings.gradle} | 0 2 files changed, 8 insertions(+), 12 deletions(-) rename modules/hivemq/{build.gradle.kts => build.gradle} (79%) rename modules/hivemq/{settings.gradle.kts => settings.gradle} (100%) diff --git a/modules/hivemq/build.gradle.kts b/modules/hivemq/build.gradle similarity index 79% rename from modules/hivemq/build.gradle.kts rename to modules/hivemq/build.gradle index 787534d7148..109061e788d 100644 --- a/modules/hivemq/build.gradle.kts +++ b/modules/hivemq/build.gradle @@ -1,9 +1,5 @@ description = "TestContainers :: HiveMQ" -plugins { - `java-library` -} - dependencies { api(project(":testcontainers")) api("org.jetbrains:annotations:23.0.0") @@ -20,10 +16,10 @@ dependencies { This would lead to issues when the HiveMQ container is included in maven projects. */ shaded("org.codehaus.plexus:plexus-utils:3.2.1") shaded("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-api-maven-embedded:3.1.4") { - exclude("org.codehouse.plexus", "plexus-utils") + exclude(group: "org.codehouse.plexus", module: "plexus-utils") } runtimeOnly("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-impl-maven-embedded:3.1.4") { - exclude("org.codehouse.plexus", "plexus-utils") + exclude(group: "org.codehouse.plexus", module: "plexus-utils") } testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") @@ -31,15 +27,15 @@ dependencies { testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.13") testImplementation("ch.qos.logback:logback-classic:1.2.3") - + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' } -tasks.withType { +test { useJUnitPlatform() } -tasks.named("compileTestJava") { - javaCompiler.set(javaToolchains.compilerFor { - languageVersion.set(JavaLanguageVersion.of(11)) - }) +tasks.compileTestJava { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(11) + } } diff --git a/modules/hivemq/settings.gradle.kts b/modules/hivemq/settings.gradle similarity index 100% rename from modules/hivemq/settings.gradle.kts rename to modules/hivemq/settings.gradle From 508af7137a0e46dafdadc94a666925dccea28da0 Mon Sep 17 00:00:00 2001 From: yannick Date: Tue, 11 Jan 2022 09:27:03 +0100 Subject: [PATCH 26/30] removed settings.gradle --- modules/hivemq/settings.gradle | 1 - 1 file changed, 1 deletion(-) delete mode 100644 modules/hivemq/settings.gradle diff --git a/modules/hivemq/settings.gradle b/modules/hivemq/settings.gradle deleted file mode 100644 index f3d5bcba948..00000000000 --- a/modules/hivemq/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include(":testcontainers") From 7f9a34e6a01ec6a2bd85c21baaee185f95efb9dc Mon Sep 17 00:00:00 2001 From: yannick Date: Tue, 11 Jan 2022 10:02:27 +0100 Subject: [PATCH 27/30] added logging events configuration to build.gradle --- modules/hivemq/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 109061e788d..62c06ddf8f8 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -32,6 +32,9 @@ dependencies { test { useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } } tasks.compileTestJava { From 53fe224cd7da9bece4dda40de944001450da56f6 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 11 Jan 2022 12:05:43 +0100 Subject: [PATCH 28/30] Isolated hivemq CI job --- .github/workflows/ci.yml | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93f8307178f..7fc8c945a49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,35 +18,9 @@ jobs: - uses: actions/checkout@v2 - id: thundra_test_initializer uses: thundra-io/thundra-test-init-action@v1 - find_gradle_jobs: - runs-on: ubuntu-18.04 - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2.3.1 - with: - java-version: '8.0.302' - distribution: temurin - - name: Cache Gradle Home files - uses: actions/cache@v2.1.6 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-home-testmatrix-${{ hashFiles('**/*.gradle') }} - - id: set-matrix - env: - # Since we override the tests executor, - # we should not push empty results to the cache - READ_ONLY_REMOTE_GRADLE_CACHE: true - run: | - TASKS=$(./gradlew --no-daemon --parallel -q testMatrix) - echo $TASKS - echo "::set-output name=matrix::{\"gradle_args\":$TASKS}" + check: - needs: [find_gradle_jobs, thundra_test_initializer] - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.find_gradle_jobs.outputs.matrix) }} + needs: [thundra_test_initializer] runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 @@ -70,7 +44,7 @@ jobs: project_id: ${{ secrets.THUNDRA_PROJECT_ID }} - name: Build and test with Gradle (${{matrix.gradle_args}}) run: | - ./gradlew --no-daemon --continue --scan ${{matrix.gradle_args}} \ + ./gradlew --no-daemon --continue --scan :hivemq:check \ $([[ -f $THUNDRA_GRADLE_INIT_SCRIPT_PATH ]] && echo "--init-script $THUNDRA_GRADLE_INIT_SCRIPT_PATH") env: THUNDRA_AGENT_TEST_RUN_ID: ${{ needs.thundra_test_initializer.outputs.thundra_agent_testrun_id }} From 3634d5b616a2f932c7e748cb87aebd21b0391f64 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 11 Jan 2022 12:20:36 +0100 Subject: [PATCH 29/30] Configure tests to use JRE 11 --- modules/hivemq/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 62c06ddf8f8..09bc1ca0060 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -42,3 +42,9 @@ tasks.compileTestJava { languageVersion = JavaLanguageVersion.of(11) } } + +tasks.test { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(11) + } +} From 931f09ebc3b099cfd0f851d671c7272db59a09e0 Mon Sep 17 00:00:00 2001 From: Kevin Wittek Date: Tue, 11 Jan 2022 12:42:41 +0100 Subject: [PATCH 30/30] Use Java 11 in Gradle extension example --- .../hivemq/src/test/resources/gradle-extension/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/hivemq/src/test/resources/gradle-extension/build.gradle b/modules/hivemq/src/test/resources/gradle-extension/build.gradle index ed924772b4c..2831ab79c37 100644 --- a/modules/hivemq/src/test/resources/gradle-extension/build.gradle +++ b/modules/hivemq/src/test/resources/gradle-extension/build.gradle @@ -15,3 +15,8 @@ hivemqExtension { sdkVersion = '4.4.1' } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +}