From f513d45b4e51fad4687830b4b9018593bb868c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Tue, 24 Sep 2024 19:29:08 -0600 Subject: [PATCH 1/3] Add RabbitMQ Stream service connection from RabbitMQContainer Add `RabbitStreamConnectionDetails` and support from `RabbitMQContainer` when `rabbitmq_stream` plugin is enabled. --- .../amqp/RabbitStreamConfiguration.java | 38 +++++- .../amqp/RabbitStreamConnectionDetails.java | 41 ++++++ .../amqp/RabbitStreamConfigurationTests.java | 54 +++++++- .../spring-boot-testcontainers/build.gradle | 1 + ...nectionDetailsFactoryIntegrationTests.java | 129 ++++++++++++++++++ ...reamContainerConnectionDetailsFactory.java | 69 ++++++++++ .../main/resources/META-INF/spring.factories | 1 + 7 files changed, 321 insertions(+), 12 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java create mode 100644 spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java index fa2ec57e7ff2..1421637b26bd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java @@ -25,6 +25,7 @@ import org.springframework.amqp.rabbit.config.ContainerCustomizer; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.amqp.RabbitProperties.Stream; import org.springframework.boot.autoconfigure.amqp.RabbitProperties.StreamContainer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -50,6 +51,12 @@ @ConditionalOnClass(StreamRabbitListenerContainerFactory.class) class RabbitStreamConfiguration { + @Bean + @ConditionalOnMissingBean(RabbitStreamConnectionDetails.class) + RabbitStreamConnectionDetails rabbitStreamConnectionDetails(RabbitProperties rabbitProperties) { + return new PropertiesRabbitStreamConnectionDetails(rabbitProperties.getStream()); + } + @Bean(name = "rabbitListenerContainerFactory") @ConditionalOnMissingBean(name = "rabbitListenerContainerFactory") @ConditionalOnProperty(prefix = "spring.rabbitmq.listener", name = "type", havingValue = "stream") @@ -68,9 +75,9 @@ StreamRabbitListenerContainerFactory streamRabbitListenerContainerFactory(Enviro @Bean(name = "rabbitStreamEnvironment") @ConditionalOnMissingBean(name = "rabbitStreamEnvironment") - Environment rabbitStreamEnvironment(RabbitProperties properties, + Environment rabbitStreamEnvironment(RabbitProperties properties, RabbitStreamConnectionDetails connectionDetails, ObjectProvider customizers) { - EnvironmentBuilder builder = configure(Environment.builder(), properties); + EnvironmentBuilder builder = configure(Environment.builder(), properties, connectionDetails); customizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); return builder.build(); } @@ -99,12 +106,13 @@ RabbitStreamTemplate rabbitStreamTemplate(Environment rabbitStreamEnvironment, R return template; } - static EnvironmentBuilder configure(EnvironmentBuilder builder, RabbitProperties properties) { + static EnvironmentBuilder configure(EnvironmentBuilder builder, RabbitProperties properties, + RabbitStreamConnectionDetails connectionDetails) { builder.lazyInitialization(true); RabbitProperties.Stream stream = properties.getStream(); PropertyMapper map = PropertyMapper.get(); - map.from(stream.getHost()).to(builder::host); - map.from(stream.getPort()).to(builder::port); + map.from(connectionDetails.getHost()).to(builder::host); + map.from(connectionDetails.getPort()).to(builder::port); map.from(stream.getVirtualHost()) .as(withFallback(properties::getVirtualHost)) .whenNonNull() @@ -118,4 +126,24 @@ private static Function withFallback(Supplier fallback) return (value) -> (value != null) ? value : fallback.get(); } + static class PropertiesRabbitStreamConnectionDetails implements RabbitStreamConnectionDetails { + + private final Stream streamProperties; + + PropertiesRabbitStreamConnectionDetails(Stream streamProperties) { + this.streamProperties = streamProperties; + } + + @Override + public String getHost() { + return this.streamProperties.getHost(); + } + + @Override + public int getPort() { + return this.streamProperties.getPort(); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java new file mode 100644 index 000000000000..1397b462ead1 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2024 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.autoconfigure.amqp; + +import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails; + +/** + * Details required to establish a connection to a RabbitMQ service. + * + * @author Eddú Meléndez + * @since 3.4.0 + */ +public interface RabbitStreamConnectionDetails extends ConnectionDetails { + + /** + * Rabbit server host. + * @return the rabbit server host + */ + String getHost(); + + /** + * Rabbit server port. + * @return the rabbit server port + */ + int getPort(); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfigurationTests.java index e7d05326cfaa..d191b8f7f7be 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfigurationTests.java @@ -17,7 +17,9 @@ package org.springframework.boot.autoconfigure.amqp; import java.time.Duration; +import java.util.List; +import com.rabbitmq.stream.Address; import com.rabbitmq.stream.BackOffDelayPolicy; import com.rabbitmq.stream.Codec; import com.rabbitmq.stream.Environment; @@ -32,6 +34,7 @@ import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.amqp.RabbitStreamConfiguration.PropertiesRabbitStreamConnectionDetails; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -43,6 +46,7 @@ import org.springframework.rabbit.stream.producer.ProducerCustomizer; import org.springframework.rabbit.stream.producer.RabbitStreamTemplate; import org.springframework.rabbit.stream.support.converter.StreamMessageConverter; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.then; @@ -127,7 +131,7 @@ void whenCustomMessageListenerContainerFactoryIsDefinedThenAutoConfiguredContain void environmentUsesPropertyDefaultsByDefault() { EnvironmentBuilder builder = mock(EnvironmentBuilder.class); RabbitProperties properties = new RabbitProperties(); - RabbitStreamConfiguration.configure(builder, properties); + RabbitStreamConfiguration.configure(builder, properties, getRabbitConnectionDetails(properties)); then(builder).should().port(5552); then(builder).should().host("localhost"); then(builder).should().lazyInitialization(true); @@ -141,7 +145,7 @@ void whenStreamPortIsSetThenEnvironmentUsesCustomPort() { EnvironmentBuilder builder = mock(EnvironmentBuilder.class); RabbitProperties properties = new RabbitProperties(); properties.getStream().setPort(5553); - RabbitStreamConfiguration.configure(builder, properties); + RabbitStreamConfiguration.configure(builder, properties, getRabbitConnectionDetails(properties)); then(builder).should().port(5553); } @@ -150,7 +154,7 @@ void whenStreamHostIsSetThenEnvironmentUsesCustomHost() { EnvironmentBuilder builder = mock(EnvironmentBuilder.class); RabbitProperties properties = new RabbitProperties(); properties.getStream().setHost("stream.rabbit.example.com"); - RabbitStreamConfiguration.configure(builder, properties); + RabbitStreamConfiguration.configure(builder, properties, getRabbitConnectionDetails(properties)); then(builder).should().host("stream.rabbit.example.com"); } @@ -159,7 +163,7 @@ void whenStreamVirtualHostIsSetThenEnvironmentUsesCustomVirtualHost() { EnvironmentBuilder builder = mock(EnvironmentBuilder.class); RabbitProperties properties = new RabbitProperties(); properties.getStream().setVirtualHost("stream-virtual-host"); - RabbitStreamConfiguration.configure(builder, properties); + RabbitStreamConfiguration.configure(builder, properties, getRabbitConnectionDetails(properties)); then(builder).should().virtualHost("stream-virtual-host"); } @@ -168,7 +172,7 @@ void whenStreamVirtualHostIsNotSetButDefaultVirtualHostIsSetThenEnvironmentUsesD EnvironmentBuilder builder = mock(EnvironmentBuilder.class); RabbitProperties properties = new RabbitProperties(); properties.setVirtualHost("default-virtual-host"); - RabbitStreamConfiguration.configure(builder, properties); + RabbitStreamConfiguration.configure(builder, properties, getRabbitConnectionDetails(properties)); then(builder).should().virtualHost("default-virtual-host"); } @@ -178,7 +182,7 @@ void whenStreamCredentialsAreNotSetThenEnvironmentUsesRabbitCredentials() { RabbitProperties properties = new RabbitProperties(); properties.setUsername("alice"); properties.setPassword("secret"); - RabbitStreamConfiguration.configure(builder, properties); + RabbitStreamConfiguration.configure(builder, properties, getRabbitConnectionDetails(properties)); then(builder).should().username("alice"); then(builder).should().password("secret"); } @@ -191,7 +195,7 @@ void whenStreamCredentialsAreSetThenEnvironmentUsesStreamCredentials() { properties.setPassword("secret"); properties.getStream().setUsername("bob"); properties.getStream().setPassword("confidential"); - RabbitStreamConfiguration.configure(builder, properties); + RabbitStreamConfiguration.configure(builder, properties, getRabbitConnectionDetails(properties)); then(builder).should().username("bob"); then(builder).should().password("confidential"); } @@ -260,6 +264,22 @@ void environmentCreatedByBuilderCanBeCustomized() { }); } + @Test + @SuppressWarnings("unchecked") + void connectionDetailsAreApplied() { + this.contextRunner.withPropertyValues("spring.rabbitmq.stream.name:stream-test") + .withUserConfiguration(CustomConnectionDetails.class) + .run((context) -> assertThat(context.getBean(Environment.class)) + .extracting((environment) -> (List
) ReflectionTestUtils.getField(environment, "addresses")) + .extracting((address) -> address.get(0)) + .extracting("host", "port") + .containsExactly("rabbitmq", 5555)); + } + + private RabbitStreamConnectionDetails getRabbitConnectionDetails(RabbitProperties properties) { + return new PropertiesRabbitStreamConnectionDetails(properties.getStream()); + } + @Configuration(proxyBeanMethods = false) static class TestConfiguration { @@ -345,4 +365,24 @@ EnvironmentBuilderCustomizer customizerB() { } + @Configuration(proxyBeanMethods = false) + static class CustomConnectionDetails { + + @Bean + RabbitStreamConnectionDetails customRabbitMqStreamConnectionDetails() { + return new RabbitStreamConnectionDetails() { + @Override + public String getHost() { + return "rabbitmq"; + } + + @Override + public int getPort() { + return 5555; + } + }; + } + + } + } diff --git a/spring-boot-project/spring-boot-testcontainers/build.gradle b/spring-boot-project/spring-boot-testcontainers/build.gradle index ce5c93a6be85..ed41155805f3 100644 --- a/spring-boot-project/spring-boot-testcontainers/build.gradle +++ b/spring-boot-project/spring-boot-testcontainers/build.gradle @@ -46,6 +46,7 @@ dependencies { dockerTestImplementation("org.springframework:spring-jms") dockerTestImplementation("org.springframework:spring-r2dbc") dockerTestImplementation("org.springframework.amqp:spring-rabbit") + dockerTestImplementation("org.springframework.amqp:spring-rabbit-stream") dockerTestImplementation("org.springframework.data:spring-data-redis") dockerTestImplementation("org.springframework.kafka:spring-kafka") dockerTestImplementation("org.springframework.ldap:spring-ldap-core") diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 000000000000..24e71c304fd6 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2012-2024 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.testcontainers.service.connection.amqp; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +import com.rabbitmq.stream.Address; +import com.rabbitmq.stream.Environment; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.RabbitMQContainer; +import org.testcontainers.images.builder.Transferable; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.amqp.EnvironmentBuilderCustomizer; +import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; +import org.springframework.boot.autoconfigure.amqp.RabbitStreamConnectionDetails; +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.rabbit.stream.producer.RabbitStreamTemplate; +import org.springframework.rabbit.stream.support.StreamAdmin; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link RabbitStreamContainerConnectionDetailsFactory}. + * + * @author Eddú Meléndez + */ +@SpringJUnitConfig +@TestPropertySource( + properties = { "spring.rabbitmq.stream.name=stream.queue1", "spring.rabbitmq.listener.type=stream" }) +@Testcontainers(disabledWithoutDocker = true) +class RabbitStreamContainerConnectionDetailsFactoryIntegrationTests { + + private static final int RABBITMQ_STREAMS_PORT = 5552; + + @Container + @ServiceConnection + static final RabbitMQContainer rabbit = getRabbitMqStreamContainer(); + + private static RabbitMQContainer getRabbitMqStreamContainer() { + RabbitMQContainer container = TestImage.container(RabbitMQContainer.class); + container.addExposedPorts(RABBITMQ_STREAMS_PORT); + var enabledPlugins = "[rabbitmq_stream,rabbitmq_prometheus]."; + container.withCopyToContainer(Transferable.of(enabledPlugins), "/etc/rabbitmq/enabled_plugins"); + return container; + } + + @Autowired(required = false) + private RabbitStreamConnectionDetails connectionDetails; + + @Autowired + private RabbitStreamTemplate rabbitStreamTemplate; + + @Autowired + private TestListener listener; + + @Test + void connectionCanBeMadeToRabbitContainer() { + assertThat(this.connectionDetails).isNotNull(); + this.rabbitStreamTemplate.convertAndSend("message"); + Awaitility.waitAtMost(Duration.ofMinutes(4)) + .untilAsserted(() -> assertThat(this.listener.messages).containsExactly("message")); + + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(RabbitAutoConfiguration.class) + static class TestConfiguration { + + @Bean + StreamAdmin streamAdmin(Environment env) { + return new StreamAdmin(env, sc -> { + sc.stream("stream.queue1").create(); + }); + } + + @Bean + EnvironmentBuilderCustomizer environmentBuilderCustomizer() { + return env -> { + Address entrypoint = new Address(rabbit.getHost(), rabbit.getMappedPort(RABBITMQ_STREAMS_PORT)); + env.addressResolver(address -> entrypoint); + }; + } + + @Bean + TestListener testListener() { + return new TestListener(); + } + + } + + static class TestListener { + + private final List messages = new ArrayList<>(); + + @RabbitListener(queues = "stream.queue1") + void processMessage(String message) { + this.messages.add(message); + } + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java new file mode 100644 index 000000000000..222f2aa53511 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2024 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.testcontainers.service.connection.amqp; + +import org.testcontainers.containers.RabbitMQContainer; + +import org.springframework.boot.autoconfigure.amqp.RabbitStreamConnectionDetails; +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 RabbitStreamConnectionDetails} from a + * {@link ServiceConnection @ServiceConnection}-annotated {@link RabbitMQContainer}. + * + * @author Eddú Meléndez + */ +class RabbitStreamContainerConnectionDetailsFactory + extends ContainerConnectionDetailsFactory { + + RabbitStreamContainerConnectionDetailsFactory() { + super(ANY_CONNECTION_NAME, "org.springframework.rabbit.stream.producer.RabbitStreamTemplate"); + } + + @Override + protected RabbitStreamConnectionDetails getContainerConnectionDetails( + ContainerConnectionSource source) { + return new RabbitMqStreamContainerConnectionDetails(source); + } + + /** + * {@link RabbitStreamConnectionDetails} backed by a + * {@link ContainerConnectionSource}. + */ + private static final class RabbitMqStreamContainerConnectionDetails + extends ContainerConnectionDetails implements RabbitStreamConnectionDetails { + + private RabbitMqStreamContainerConnectionDetails(ContainerConnectionSource source) { + super(source); + } + + @Override + public String getHost() { + return getContainer().getHost(); + } + + @Override + public int getPort() { + return getContainer().getMappedPort(5552); + } + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories index bd92b9665f14..44dc012be285 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories @@ -12,6 +12,7 @@ org.springframework.boot.testcontainers.service.connection.activemq.ActiveMQClas org.springframework.boot.testcontainers.service.connection.activemq.ActiveMQContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.activemq.ArtemisContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.amqp.RabbitContainerConnectionDetailsFactory,\ +org.springframework.boot.testcontainers.service.connection.amqp.RabbitStreamContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.cassandra.CassandraContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.couchbase.CouchbaseContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.flyway.FlywayContainerConnectionDetailsFactory,\ From 7593aabe441fd2adcc2bd87656095b95f101568d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 25 Sep 2024 14:14:15 -0600 Subject: [PATCH 2/3] Fix comments --- .../amqp/RabbitStreamConfiguration.java | 27 ++++++++++++++++--- .../amqp/RabbitStreamConnectionDetails.java | 24 +++++++++++++++++ ...nectionDetailsFactoryIntegrationTests.java | 2 +- ...reamContainerConnectionDetailsFactory.java | 10 +++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java index 1421637b26bd..57744f2863b6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConfiguration.java @@ -113,12 +113,18 @@ static EnvironmentBuilder configure(EnvironmentBuilder builder, RabbitProperties PropertyMapper map = PropertyMapper.get(); map.from(connectionDetails.getHost()).to(builder::host); map.from(connectionDetails.getPort()).to(builder::port); - map.from(stream.getVirtualHost()) + map.from(connectionDetails.getVirtualHost()) .as(withFallback(properties::getVirtualHost)) .whenNonNull() .to(builder::virtualHost); - map.from(stream.getUsername()).as(withFallback(properties::getUsername)).whenNonNull().to(builder::username); - map.from(stream.getPassword()).as(withFallback(properties::getPassword)).whenNonNull().to(builder::password); + map.from(connectionDetails.getUsername()) + .as(withFallback(properties::getUsername)) + .whenNonNull() + .to(builder::username); + map.from(connectionDetails.getPassword()) + .as(withFallback(properties::getPassword)) + .whenNonNull() + .to(builder::password); return builder; } @@ -144,6 +150,21 @@ public int getPort() { return this.streamProperties.getPort(); } + @Override + public String getVirtualHost() { + return this.streamProperties.getVirtualHost(); + } + + @Override + public String getUsername() { + return this.streamProperties.getUsername(); + } + + @Override + public String getPassword() { + return this.streamProperties.getPassword(); + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java index 1397b462ead1..a61ede70ae58 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java @@ -38,4 +38,28 @@ public interface RabbitStreamConnectionDetails extends ConnectionDetails { */ int getPort(); + /** + * Login user to authenticate to the broker. + * @return the login user to authenticate to the broker or {@code null} + */ + default String getUsername() { + return null; + } + + /** + * Login to authenticate against the broker. + * @return the login to authenticate against the broker or {@code null} + */ + default String getPassword() { + return null; + } + + /** + * Virtual host to use when connecting to the broker. + * @return the virtual host to use when connecting to the broker or {@code null} + */ + default String getVirtualHost() { + return null; + } + } diff --git a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java index 24e71c304fd6..e3bd0cdcdd4d 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java +++ b/spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java @@ -66,7 +66,7 @@ class RabbitStreamContainerConnectionDetailsFactoryIntegrationTests { private static RabbitMQContainer getRabbitMqStreamContainer() { RabbitMQContainer container = TestImage.container(RabbitMQContainer.class); container.addExposedPorts(RABBITMQ_STREAMS_PORT); - var enabledPlugins = "[rabbitmq_stream,rabbitmq_prometheus]."; + String enabledPlugins = "[rabbitmq_stream,rabbitmq_prometheus]."; container.withCopyToContainer(Transferable.of(enabledPlugins), "/etc/rabbitmq/enabled_plugins"); return container; } diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java index 222f2aa53511..019267bdb7f0 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/amqp/RabbitStreamContainerConnectionDetailsFactory.java @@ -64,6 +64,16 @@ public int getPort() { return getContainer().getMappedPort(5552); } + @Override + public String getUsername() { + return getContainer().getAdminUsername(); + } + + @Override + public String getPassword() { + return getContainer().getAdminPassword(); + } + } } From 3f149e13ea6a1a2599429eaaa2753c76d0805d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Mon, 30 Sep 2024 14:28:01 -0600 Subject: [PATCH 3/3] Polish javadoc --- .../autoconfigure/amqp/RabbitStreamConnectionDetails.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java index a61ede70ae58..652354905012 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitStreamConnectionDetails.java @@ -19,7 +19,7 @@ import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails; /** - * Details required to establish a connection to a RabbitMQ service. + * Details required to establish a connection to a RabbitMQ Stream service. * * @author Eddú Meléndez * @since 3.4.0 @@ -33,8 +33,8 @@ public interface RabbitStreamConnectionDetails extends ConnectionDetails { String getHost(); /** - * Rabbit server port. - * @return the rabbit server port + * Rabbit Stream server port. + * @return the rabbit stream server port */ int getPort();