Move Amqp testcontainers support into spring-boot-amqp

This commit is contained in:
Stéphane Nicoll
2025-05-19 14:43:46 +02:00
committed by Phillip Webb
parent abdc0fdf90
commit c8de0caaeb
9 changed files with 18 additions and 9 deletions

View File

@@ -1,5 +1,6 @@
plugins {
id "java-library"
id "org.springframework.boot.docker-test"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.deployed"
@@ -19,10 +20,17 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-testcontainers"))
optional("io.micrometer:micrometer-core")
optional("org.springframework.amqp:spring-rabbit-stream")
optional("org.testcontainers:rabbitmq")
dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker"))
dockerTestImplementation("ch.qos.logback:logback-classic")
dockerTestImplementation("org.testcontainers:junit-jupiter")
testCompileOnly("com.fasterxml.jackson.core:jackson-annotations")
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2012-2025 the original author or 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.
*/
package org.springframework.boot.amqp.testcontainers;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.RabbitMQContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;
import org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link RabbitContainerConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@SpringJUnitConfig
@Testcontainers(disabledWithoutDocker = true)
class RabbitContainerConnectionDetailsFactoryIntegrationTests {
@Container
@ServiceConnection
static final RabbitMQContainer rabbit = TestImage.container(RabbitMQContainer.class);
@Autowired(required = false)
private RabbitConnectionDetails connectionDetails;
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private TestListener listener;
@Test
void connectionCanBeMadeToRabbitContainer() {
assertThat(this.connectionDetails).isNotNull();
this.rabbitTemplate.convertAndSend("test", "message");
Awaitility.waitAtMost(Duration.ofMinutes(4))
.untilAsserted(() -> assertThat(this.listener.messages).containsExactly("message"));
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(RabbitAutoConfiguration.class)
static class TestConfiguration {
@Bean
TestListener testListener() {
return new TestListener();
}
}
static class TestListener {
private final List<String> messages = new ArrayList<>();
@RabbitListener(queuesToDeclare = @Queue("test"))
void processMessage(String message) {
this.messages.add(message);
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2012-2025 the original author or 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.
*/
package org.springframework.boot.amqp.testcontainers;
import java.net.URI;
import java.util.List;
import org.testcontainers.containers.RabbitMQContainer;
import org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
/**
* {@link ContainerConnectionDetailsFactory} to create {@link RabbitConnectionDetails}
* from a {@link ServiceConnection @ServiceConnection}-annotated
* {@link RabbitMQContainer}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class RabbitContainerConnectionDetailsFactory
extends ContainerConnectionDetailsFactory<RabbitMQContainer, RabbitConnectionDetails> {
@Override
protected RabbitConnectionDetails getContainerConnectionDetails(
ContainerConnectionSource<RabbitMQContainer> source) {
return new RabbitMqContainerConnectionDetails(source);
}
/**
* {@link RabbitConnectionDetails} backed by a {@link ContainerConnectionSource}.
*/
private static final class RabbitMqContainerConnectionDetails extends ContainerConnectionDetails<RabbitMQContainer>
implements RabbitConnectionDetails {
private RabbitMqContainerConnectionDetails(ContainerConnectionSource<RabbitMQContainer> source) {
super(source);
}
@Override
public String getUsername() {
return getContainer().getAdminUsername();
}
@Override
public String getPassword() {
return getContainer().getAdminPassword();
}
@Override
public List<Address> getAddresses() {
URI uri = URI.create((getSslBundle() != null) ? getContainer().getAmqpsUrl() : getContainer().getAmqpUrl());
return List.of(new Address(uri.getHost(), uri.getPort()));
}
@Override
public SslBundle getSslBundle() {
return super.getSslBundle();
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 the original author or 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.
*/
/**
* Support for testcontainers RabbitMQ service connections.
*/
package org.springframework.boot.amqp.testcontainers;

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\
org.springframework.boot.amqp.testcontainers.RabbitContainerConnectionDetailsFactory

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
</configuration>