Skip to content

Commit

Permalink
Merge pull request wildfly#18567 from kabir/rm-artemis-testcontainers
Browse files Browse the repository at this point in the history
[WFLY-20162] Start Artemis/AMQP in testcontainers rather than embedded
  • Loading branch information
bstansberry authored Dec 20, 2024
2 parents 457ac33 + 4ce7f91 commit 6eb3646
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,25 @@

package org.wildfly.test.integration.microprofile.reactive;

import org.apache.activemq.artemis.core.security.CheckType;
import org.apache.activemq.artemis.core.security.Role;
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
import org.jboss.as.arquillian.api.ServerSetupTask;
import org.jboss.as.arquillian.container.ManagementClient;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SYSTEM_PROPERTY;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE;
import static org.wildfly.test.integration.microprofile.reactive.KeystoreUtil.SERVER_KEYSTORE_PATH;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Set;
import java.util.Map;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;
import org.jboss.arquillian.testcontainers.api.DockerRequired;
import org.jboss.as.arquillian.api.ServerSetupTask;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.model.test.ModelTestUtils;
import org.jboss.dmr.ModelNode;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;

/**
* Setup task to start an embedded version of Artemis for AMQP support.
Expand All @@ -32,61 +33,71 @@
*
* @author <a href="mailto:[email protected]">Kabir Khan</a>
*/
@DockerRequired
public class RunArtemisAmqpSetupTask implements ServerSetupTask {
private static volatile EmbeddedActiveMQ server;
private static GenericContainer<?> container;
private volatile boolean copyKeystore = false;

private volatile String brokerXml = "messaging/amqp/broker.xml";
private volatile Path replacedBrokerXml;

private static final int AMQP_PORT = 5672;
private static final PathElement AMQP_PORT_PATH = PathElement.pathElement(SYSTEM_PROPERTY, "calculated.amqp.port");

public RunArtemisAmqpSetupTask() {
}

public RunArtemisAmqpSetupTask(String brokerXml) {
public RunArtemisAmqpSetupTask(String brokerXml, boolean copyKeystore) {
this.brokerXml = brokerXml;
this.copyKeystore = copyKeystore;
}

@Override
public void setup(ManagementClient managementClient, String containerId) throws Exception {
try {
server = new EmbeddedActiveMQ();
URL url = RunArtemisAmqpSetupTask.class.getResource(brokerXml);
Path path = Paths.get(url.toURI());
List<String> lines = Files.readAllLines(path);

// The broker.xml expects an absolute path to the server keystore. So copy it to a new location,
// and replace the '$SERVER_KEYSTORE$' placeholder with the actual location
if (!Files.exists(KeystoreUtil.KEY_STORE_DIRECTORY_PATH)) {
Files.createDirectories(KeystoreUtil.KEY_STORE_DIRECTORY_PATH);
}
replacedBrokerXml = Files.createTempFile(KeystoreUtil.KEY_STORE_DIRECTORY_PATH, "broker", "xml");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(replacedBrokerXml.toFile()))) {
String serverKeystorePath = KeystoreUtil.SERVER_KEYSTORE_PATH.toAbsolutePath().normalize().toString();
// On Windows this will parse to e.g: C:\some\where. The Artemis broker.xml parser does not like this
// so attempt to change this to C:/some/where
serverKeystorePath = serverKeystorePath.replaceAll("\\\\", "/");

for (String line : lines) {
String replaced = line.replace("$SERVER_KEYSTORE$", serverKeystorePath);
writer.write(replaced);
writer.newLine();
}

DockerImageName imageName = DockerImageName.parse("quay.io/artemiscloud/activemq-artemis-broker:1.0.32");
container = new GenericContainer<>(imageName);
container.addExposedPort(AMQP_PORT);
container.withEnv(Map.of(
"AMQ_ROLE", "amq",
"AMQ_USER", "artemis",
"AMQ_PASSWORD", "artemis",
"SCRIPT_DEBUG", "true"));
// Grant all possible file permissions since it ends up under the wrong user, and I can't find how to change
// the owner/group with testcontainers
Path path = Paths.get(RunArtemisAmqpSetupTask.class.getResource("messaging/amqp/launch.sh").toURI());
container.withCopyFileToContainer(
MountableFile.forHostPath(path, 0777),
"/opt/amq/bin/launch.sh"
);
path = Paths.get(RunArtemisAmqpSetupTask.class.getResource(brokerXml).toURI());
container.withCopyFileToContainer(
MountableFile.forHostPath(path),
"/home/jboss/config/broker.xml"
);
if (copyKeystore) {
KeystoreUtil.createKeystores();
// Copy the keystore files to the expected container location
// The subclass should have configured the keystore in the broker.xml
container.withCopyFileToContainer(
MountableFile.forHostPath(SERVER_KEYSTORE_PATH.getParent()),
"/home/jboss/config/");


}
String brokerXml = replacedBrokerXml.toUri().toURL().toExternalForm();

server.setConfigResourcePath(brokerXml);
server.setSecurityManager(new ActiveMQSecurityManager() {
@Override
public boolean validateUser(String username, String password) {
return true;
}

@Override
public boolean validateUserAndRole(String username, String password, Set<Role> set, CheckType checkType) {
return true;
}
});
server.start();
await().atMost(60, SECONDS).until(() -> server.getActiveMQServer().isStarted());
container.start();

// Set the calculated port as a property in the model
int amqpPort = container.getMappedPort(AMQP_PORT);
ModelNode op = Util.createAddOperation(PathAddress.pathAddress(AMQP_PORT_PATH), Map.of(VALUE, new ModelNode(amqpPort)));
ModelNode result = managementClient.getControllerClient().execute(op);
ModelTestUtils.checkOutcome(result);
} catch (Exception e) {
try {
tearDown(managementClient, containerId);
} catch (Exception ex) {
e.printStackTrace();
}
throw new RuntimeException(e);
}
}
Expand All @@ -95,14 +106,17 @@ public boolean validateUserAndRole(String username, String password, Set<Role> s
@Override
public void tearDown(ManagementClient managementClient, String containerId) throws Exception {
try {
if (server != null) {
server.stop();
ModelNode op = Util.createRemoveOperation(PathAddress.pathAddress(AMQP_PORT_PATH));
managementClient.getControllerClient().execute(op);

if (container != null) {
container.stop();
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (Files.exists(replacedBrokerXml)) {
Files.delete(replacedBrokerXml);
if (copyKeystore) {
KeystoreUtil.cleanUp();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.testcontainers.api.DockerRequired;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.as.test.shared.CLIServerSetupTask;
import org.jboss.as.test.shared.TimeoutUtil;
Expand All @@ -32,6 +33,7 @@
@RunWith(Arquillian.class)
@RunAsClient
@ServerSetup({RunArtemisAmqpSetupTask.class, EnableReactiveExtensionsSetupTask.class})
@DockerRequired
public class AnonymousAmqpTestCase {
@ArquillianResource
URL url;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.testcontainers.api.DockerRequired;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.test.shared.CLIServerSetupTask;
Expand All @@ -21,7 +22,6 @@
import org.junit.runner.RunWith;
import org.wildfly.test.integration.microprofile.reactive.ConfigureElytronSslContextSetupTask;
import org.wildfly.test.integration.microprofile.reactive.EnableReactiveExtensionsSetupTask;
import org.wildfly.test.integration.microprofile.reactive.KeystoreUtil;
import org.wildfly.test.integration.microprofile.reactive.RunArtemisAmqpSetupTask;

import java.net.URL;
Expand All @@ -34,6 +34,7 @@
@RunWith(Arquillian.class)
@RunAsClient
@ServerSetup({SslAmqpWithSslConfiguredGloballyTestCase.RunArtemisSslUsernamePasswordSecuredSetupTask.class, EnableReactiveExtensionsSetupTask.class, ConfigureElytronSslContextSetupTask.class})
@DockerRequired
public class SslAmqpWithSslConfiguredGloballyTestCase {
@ArquillianResource
URL url;
Expand Down Expand Up @@ -67,22 +68,7 @@ public void test() {

static class RunArtemisSslUsernamePasswordSecuredSetupTask extends RunArtemisAmqpSetupTask {
public RunArtemisSslUsernamePasswordSecuredSetupTask() {
super("messaging/amqp/broker-ssl.xml");
}

@Override
public void setup(ManagementClient managementClient, String containerId) throws Exception {
KeystoreUtil.createKeystores();
super.setup(managementClient, containerId);
}

@Override
public void tearDown(ManagementClient managementClient, String containerId) throws Exception {
try {
super.tearDown(managementClient, containerId);
} finally {
KeystoreUtil.cleanUp();
}
super("messaging/amqp/broker-ssl.xml", true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.arquillian.testcontainers.api.DockerRequired;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.test.shared.CLIServerSetupTask;
Expand All @@ -21,7 +22,6 @@
import org.junit.runner.RunWith;
import org.wildfly.test.integration.microprofile.reactive.ConfigureElytronSslContextSetupTask;
import org.wildfly.test.integration.microprofile.reactive.EnableReactiveExtensionsSetupTask;
import org.wildfly.test.integration.microprofile.reactive.KeystoreUtil;
import org.wildfly.test.integration.microprofile.reactive.RunArtemisAmqpSetupTask;

import java.net.URL;
Expand All @@ -34,6 +34,7 @@
@RunWith(Arquillian.class)
@RunAsClient
@ServerSetup({SslAmqpWithSslConfiguredOnConnectorTestCase.RunArtemisSslUsernamePasswordSecuredSetupTask.class, EnableReactiveExtensionsSetupTask.class, ConfigureElytronSslContextSetupTask.class})
@DockerRequired
public class SslAmqpWithSslConfiguredOnConnectorTestCase {
@ArquillianResource
URL url;
Expand Down Expand Up @@ -67,22 +68,7 @@ public void test() {

static class RunArtemisSslUsernamePasswordSecuredSetupTask extends RunArtemisAmqpSetupTask {
public RunArtemisSslUsernamePasswordSecuredSetupTask() {
super("messaging/amqp/broker-ssl.xml");
}

@Override
public void setup(ManagementClient managementClient, String containerId) throws Exception {
KeystoreUtil.createKeystores();
super.setup(managementClient, containerId);
}

@Override
public void tearDown(ManagementClient managementClient, String containerId) throws Exception {
try {
super.tearDown(managementClient, containerId);
} finally {
KeystoreUtil.cleanUp();
}
super("messaging/amqp/broker-ssl.xml", true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

amqp-host=localhost
amqp-port=5672
amqp-port=${calculated.amqp.port}
amqp-username=artemis
amqp-password=artemis

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

mp.messaging.outgoing.source.connector=smallrye-amqp
mp.messaging.outgoing.source.wildfly.elytron.ssl.context=kafka-ssl-test
mp.messaging.outgoing.source.port=5672
mp.messaging.outgoing.source.port=${calculated.amqp.port}
mp.messaging.outgoing.source.username=artemis
mp.messaging.outgoing.source.password=artemis
mp.messaging.outgoing.source.use-ssl=true

mp.messaging.incoming.in.connector=smallrye-amqp
mp.messaging.incoming.in.address=source
mp.messaging.incoming.in.wildfly.elytron.ssl.context=kafka-ssl-test
mp.messaging.incoming.in.port=5672
mp.messaging.incoming.in.port=${calculated.amqp.port}
mp.messaging.incoming.in.username=artemis
mp.messaging.incoming.in.password=artemis
mp.messaging.incoming.in.use-ssl=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
#

amqp-port=5672
amqp-port=${calculated.amqp.port}
amqp-username=artemis
amqp-password=artemis
amqp-use-ssl=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright The WildFly Authors
# SPDX-License-Identifier: Apache-2.0
#
amqp-port=${calculated.amqp.port}

mp.messaging.outgoing.source.connector=smallrye-amqp
mp.messaging.outgoing.source.address=testing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Copyright The WildFly Authors
# SPDX-License-Identifier: Apache-2.0
#
amqp-port=${calculated.amqp.port}

mp.messaging.outgoing.amqp.connector=smallrye-amqp
mp.messaging.outgoing.amqp.address=testing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

amqp-host=localhost
amqp-port=5672
amqp-port=${calculated.amqp.port}
amqp-username=artemis
amqp-password=artemis

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<acceptor name="artemis">tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true</acceptor>

<!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic - secured with SSL. -->
<acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true;sslEnabled=true;keyStorePath=$SERVER_KEYSTORE$;keyStorePassword=serverks</acceptor>
<acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true;sslEnabled=true;keyStorePath=/home/jboss/config/server.keystore.p12;keyStorePassword=serverks</acceptor>
</acceptors>


Expand Down
Loading

0 comments on commit 6eb3646

Please sign in to comment.