Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Support legacy RabbitMQ configuration format #1692

Merged
merged 5 commits into from Aug 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -346,16 +346,42 @@ public RabbitMQContainer withExchange(String name, String type, boolean autoDele
}

/**
* Overwrites the default RabbitMQ configuration file with the supplied one
* Overwrites the default RabbitMQ configuration file with the supplied one.
*
* @param rabbitMQConf The rabbitmq.conf file to use
* @param rabbitMQConf The rabbitmq.conf file to use (in sysctl format, don't forget empty line in the end of file)
* @return This container.
*/
public RabbitMQContainer withRabbitMQConfig(MountableFile rabbitMQConf) {
withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom.conf");

return withRabbitMQConfigSysctl(rabbitMQConf);
}

/**
* Overwrites the default RabbitMQ configuration file with the supplied one.
*
* This function doesn't work with RabbitMQ < 3.7.
*
* This function and the Sysctl format is recommended for RabbitMQ >= 3.7
*
* @param rabbitMQConf The rabbitmq.config file to use (in sysctl format, don't forget empty line in the end of file)
* @return This container.
*/
public RabbitMQContainer withRabbitMQConfigSysctl(MountableFile rabbitMQConf) {
withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom");
return withCopyFileToContainer(rabbitMQConf, "/etc/rabbitmq/rabbitmq-custom.conf");
}

/**
* Overwrites the default RabbitMQ configuration file with the supplied one.
*
* @param rabbitMQConf The rabbitmq.config file to use (in erlang format)
* @return This container.
*/
public RabbitMQContainer withRabbitMQConfigErlang(MountableFile rabbitMQConf) {
withEnv("RABBITMQ_CONFIG_FILE", "/etc/rabbitmq/rabbitmq-custom.config");
return withCopyFileToContainer(rabbitMQConf, "/etc/rabbitmq/rabbitmq-custom.config");
}

@NotNull
private String toJson(Map<String, Object> arguments) {
try {
Expand Down
@@ -1,26 +1,29 @@
package org.testcontainers.containers;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER;
import static org.testcontainers.utility.MountableFile.forClasspathResource;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.junit.Test;
import org.testcontainers.utility.MountableFile;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.testcontainers.containers.RabbitMQContainer.SslVerification.VERIFY_PEER;
import static org.testcontainers.utility.MountableFile.forClasspathResource;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.junit.Test;
import org.testcontainers.utility.MountableFile;

/**
* @author Martin Greber
Expand All @@ -34,7 +37,8 @@ public class RabbitMQContainerTest {
public static final int DEFAULT_HTTP_PORT = 15672;

@Test
public void shouldCreateRabbitMQContainer() {
public void shouldCreateRabbitMQContainer()
{
try (RabbitMQContainer container = new RabbitMQContainer()) {

assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE);
Expand All @@ -44,163 +48,199 @@ public void shouldCreateRabbitMQContainer() {
container.start();

assertThat(container.getAmqpsUrl()).isEqualTo(
String.format("amqps://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQPS_PORT)));
String.format("amqps://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQPS_PORT)));
assertThat(container.getAmqpUrl()).isEqualTo(
String.format("amqp://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQP_PORT)));
String.format("amqp://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_AMQP_PORT)));
assertThat(container.getHttpsUrl()).isEqualTo(
String.format("https://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTPS_PORT)));
String.format("https://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTPS_PORT)));
assertThat(container.getHttpUrl()).isEqualTo(
String.format("http://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTP_PORT)));
String.format("http://%s:%d", container.getContainerIpAddress(), container.getMappedPort(DEFAULT_HTTP_PORT)));

assertThat(container.getHttpsPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTPS_PORT));
assertThat(container.getHttpPort()).isEqualTo(container.getMappedPort(DEFAULT_HTTP_PORT));
assertThat(container.getAmqpsPort()).isEqualTo(container.getMappedPort(DEFAULT_AMQPS_PORT));
assertThat(container.getAmqpPort()).isEqualTo(container.getMappedPort(DEFAULT_AMQP_PORT));

assertThat(container.getLivenessCheckPortNumbers()).containsExactlyInAnyOrder(
container.getMappedPort(DEFAULT_AMQP_PORT),
container.getMappedPort(DEFAULT_AMQPS_PORT),
container.getMappedPort(DEFAULT_HTTP_PORT),
container.getMappedPort(DEFAULT_HTTPS_PORT)
container.getMappedPort(DEFAULT_AMQP_PORT),
container.getMappedPort(DEFAULT_AMQPS_PORT),
container.getMappedPort(DEFAULT_HTTP_PORT),
container.getMappedPort(DEFAULT_HTTPS_PORT)
);
}
}

@Test
public void shouldCreateRabbitMQContainerWithTag() {
public void shouldCreateRabbitMQContainerWithTag()
{
try (RabbitMQContainer container = new RabbitMQContainer(DEFAULT_IMAGE)) {
assertThat(container.getDockerImageName()).isEqualTo(DEFAULT_IMAGE);
}
}

@Test
public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException {
public void shouldCreateRabbitMQContainerWithExchange() throws IOException, InterruptedException
{
try (RabbitMQContainer container = new RabbitMQContainer()) {
container.withExchange("test-exchange", "direct");

container.start();

assertThat(container.execInContainer("rabbitmqctl", "list_exchanges").getStdout())
.containsPattern("test-exchange\\s+direct");
.containsPattern("test-exchange\\s+direct");
}
}

@Test
public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException {
public void shouldCreateRabbitMQContainerWithQueues() throws IOException, InterruptedException
{
try (RabbitMQContainer container = new RabbitMQContainer()) {

container.withQueue("queue-one")
.withQueue("queue-two", false, true, ImmutableMap.of("x-message-ttl", 1000));
.withQueue("queue-two", false, true, ImmutableMap.of("x-message-ttl", 1000));

container.start();

assertThat(container.execInContainer("rabbitmqctl", "list_queues", "name", "arguments").getStdout())
.containsPattern("queue-one");
.containsPattern("queue-one");
assertThat(container.execInContainer("rabbitmqctl", "list_queues", "name", "arguments").getStdout())
.containsPattern("queue-two\\s.*x-message-ttl");
.containsPattern("queue-two\\s.*x-message-ttl");
}
}

@Test
public void shouldMountConfigurationFile()
{
try (RabbitMQContainer container = new RabbitMQContainer()) {

container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf"));
container.start();

assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.conf");
assertThat(container.getLogs()).doesNotContain(" (not found)");
}
}


@Test
public void shouldMountConfigurationFileErlang()
{
try (RabbitMQContainer container = new RabbitMQContainer()) {

container.withRabbitMQConfigErlang(MountableFile.forClasspathResource("/rabbitmq-custom.config"));
container.start();

assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.config");
assertThat(container.getLogs()).doesNotContain(" (not found)");
}
}


@Test
public void shouldMountConfigurationFile() {
public void shouldMountConfigurationFileSysctl()
{
try (RabbitMQContainer container = new RabbitMQContainer()) {

container.withRabbitMQConfig(MountableFile.forClasspathResource("/rabbitmq-custom.conf"));
container.start();

assertThat(container.getLogs().contains("/etc/rabbitmq/rabbitmq-custom.conf")).isTrue();
assertThat(container.getLogs()).contains("config file(s) : /etc/rabbitmq/rabbitmq-custom.conf");
assertThat(container.getLogs()).doesNotContain(" (not found)");
}
}

@Test
public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException {
public void shouldStartTheWholeEnchilada() throws IOException, InterruptedException
{
try (RabbitMQContainer container = new RabbitMQContainer()) {
container
.withVhost("vhost1")
.withVhostLimit("vhost1", "max-connections", 1)
.withVhost("vhost2", true)
.withExchange("direct-exchange", "direct")
.withExchange("topic-exchange", "topic")
.withQueue("queue1")
.withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000))
.withBinding("direct-exchange", "queue1")
.withUser("user1", "password1")
.withUser("user2", "password2", ImmutableSet.of("administrator"))
.withPermission("vhost1", "user1", ".*", ".*", ".*")
.withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues")
.withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct"))
.withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues")
.withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange");
.withVhost("vhost1")
.withVhostLimit("vhost1", "max-connections", 1)
.withVhost("vhost2", true)
.withExchange("direct-exchange", "direct")
.withExchange("topic-exchange", "topic")
.withQueue("queue1")
.withQueue("queue2", true, false, ImmutableMap.of("x-message-ttl", 1000))
.withBinding("direct-exchange", "queue1")
.withUser("user1", "password1")
.withUser("user2", "password2", ImmutableSet.of("administrator"))
.withPermission("vhost1", "user1", ".*", ".*", ".*")
.withPolicy("max length policy", "^dog", ImmutableMap.of("max-length", 1), 1, "queues")
.withPolicy("alternate exchange policy", "^direct-exchange", ImmutableMap.of("alternate-exchange", "amq.direct"))
.withOperatorPolicy("operator policy 1", "^queue1", ImmutableMap.of("message-ttl", 1000), 1, "queues")
.withPluginsEnabled("rabbitmq_shovel", "rabbitmq_random_exchange");

container.start();

assertThat(container.execInContainer("rabbitmqadmin", "list", "queues")
.getStdout())
.contains("queue1", "queue2");
.getStdout())
.contains("queue1", "queue2");

assertThat(container.execInContainer("rabbitmqadmin", "list", "exchanges")
.getStdout())
.contains("direct-exchange", "topic-exchange");
.getStdout())
.contains("direct-exchange", "topic-exchange");

assertThat(container.execInContainer("rabbitmqadmin", "list", "bindings")
.getStdout())
.contains("direct-exchange");
.getStdout())
.contains("direct-exchange");

assertThat(container.execInContainer("rabbitmqadmin", "list", "users")
.getStdout())
.contains("user1", "user2");
.getStdout())
.contains("user1", "user2");

assertThat(container.execInContainer("rabbitmqadmin", "list", "policies")
.getStdout())
.contains("max length policy", "alternate exchange policy");
.getStdout())
.contains("max length policy", "alternate exchange policy");

assertThat(container.execInContainer("rabbitmqadmin", "list", "operator_policies")
.getStdout())
.contains("operator policy 1");
.getStdout())
.contains("operator policy 1");

assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_shovel", "--quiet")
.getStdout())
.contains("rabbitmq_shovel is enabled");
.getStdout())
.contains("rabbitmq_shovel is enabled");

assertThat(container.execInContainer("rabbitmq-plugins", "is_enabled", "rabbitmq_random_exchange", "--quiet")
.getStdout())
.contains("rabbitmq_random_exchange is enabled");
.getStdout())
.contains("rabbitmq_random_exchange is enabled");
}
}

@Test
public void shouldThrowExceptionForDodgyJson() {
public void shouldThrowExceptionForDodgyJson()
{
try (RabbitMQContainer container = new RabbitMQContainer()) {

assertThatCode(() ->
container.withQueue(
"queue2",
true,
false,
ImmutableMap.of("x-message-ttl", container))
container.withQueue(
"queue2",
true,
false,
ImmutableMap.of("x-message-ttl", container))
).hasMessageStartingWith("Failed to convert arguments into json");

}
}

@Test
public void shouldWorkWithSSL() {
public void shouldWorkWithSSL()
{
try (RabbitMQContainer container = new RabbitMQContainer()) {
container.withSSL(
forClasspathResource("/certs/server_key.pem", 0644),
forClasspathResource("/certs/server_certificate.pem", 0644),
forClasspathResource("/certs/ca_certificate.pem", 0644),
VERIFY_PEER,
true
forClasspathResource("/certs/server_key.pem", 0644),
forClasspathResource("/certs/server_certificate.pem", 0644),
forClasspathResource("/certs/ca_certificate.pem", 0644),
VERIFY_PEER,
true
);

container.start();

assertThatCode(() -> {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.useSslProtocol(createSslContext(
"certs/client_key.p12", "password",
"certs/truststore.jks", "password"));
"certs/client_key.p12", "password",
"certs/truststore.jks", "password"));
connectionFactory.enableHostnameVerification();
connectionFactory.setUri(container.getAmqpsUrl());
connectionFactory.setPassword(container.getAdminPassword());
Expand All @@ -213,7 +253,8 @@ public void shouldWorkWithSSL() {
}

private SSLContext createSslContext(String keystoreFile, String keystorePassword, String truststoreFile, String truststorePassword)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException {
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException
{
ClassLoader classLoader = getClass().getClassLoader();

KeyStore ks = KeyStore.getInstance("PKCS12");
Expand Down
2 changes: 1 addition & 1 deletion modules/rabbitmq/src/test/resources/rabbitmq-custom.conf
@@ -1,2 +1,2 @@
loopback_users.guest = false
listeners.tcp.default = 5555
listeners.tcp.default = 5555
13 changes: 13 additions & 0 deletions modules/rabbitmq/src/test/resources/rabbitmq-custom.config
@@ -0,0 +1,13 @@
[
{ rabbit, [
{ loopback_users, [ ] },
{ tcp_listeners, [ 5555 ] },
{ ssl_listeners, [ ] },
{ default_vhost, <<"vhost">> },
{ hipe_compile, false }
] },
{ rabbitmq_management, [ { listener, [
{ port, 15672 },
{ ssl, false }
] } ] }
].