diff --git a/dina-base-api/pom.xml b/dina-base-api/pom.xml index ac73f1083..822dfbecc 100644 --- a/dina-base-api/pom.xml +++ b/dina-base-api/pom.xml @@ -8,7 +8,7 @@ io.github.aafc-bicoe dina-base-parent - 0.116 + 0.117 dina-base-api @@ -144,7 +144,7 @@ io.github.aafc-bicoe dina-test-support - 0.116 + 0.117 test diff --git a/dina-client/pom.xml b/dina-client/pom.xml index 4c5343764..a63ab76d8 100644 --- a/dina-client/pom.xml +++ b/dina-client/pom.xml @@ -8,7 +8,7 @@ io.github.aafc-bicoe dina-base-parent - 0.116 + 0.117 dina-client diff --git a/dina-messaging/pom.xml b/dina-messaging/pom.xml index a87b50681..e30671f40 100644 --- a/dina-messaging/pom.xml +++ b/dina-messaging/pom.xml @@ -8,7 +8,7 @@ io.github.aafc-bicoe dina-base-parent - 0.116 + 0.117 dina-messaging @@ -35,6 +35,12 @@ ${testcontainers.version} test + + io.github.aafc-bicoe + dina-test-support + 0.117 + test + diff --git a/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/config/RabbitMQConfig.java b/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/config/RabbitMQConfig.java index c4b9c84b8..9165bb3c5 100644 --- a/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/config/RabbitMQConfig.java +++ b/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/config/RabbitMQConfig.java @@ -9,20 +9,25 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import java.util.Optional; import javax.inject.Inject; +import lombok.extern.log4j.Log4j2; /** * Configuration of RabbitMQ related beans */ +@Log4j2 @Configuration @Conditional(MessagingConfigurationCondition.class) public class RabbitMQConfig { private final RabbitMQProperties rmqProps; + private final RabbitTemplate.ReturnsCallback returnCallback; @Inject - public RabbitMQConfig(RabbitMQProperties rmqProps) { + public RabbitMQConfig(RabbitMQProperties rmqProps, Optional returnCallback) { this.rmqProps = rmqProps; + this.returnCallback = returnCallback.orElse(null); } @Bean @@ -31,6 +36,9 @@ protected ConnectionFactory createConnectionFactory() { cachingConnectionFactory.setUsername(rmqProps.getUsername()); cachingConnectionFactory.setPassword(rmqProps.getPassword()); + // allow to get messages that can't be delivered back + cachingConnectionFactory.setPublisherReturns(true); + if(rmqProps.getPort() > 0) { cachingConnectionFactory.setPort(rmqProps.getPort()); } @@ -48,6 +56,16 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); rabbitTemplate.setMessageConverter(createMessageConverter()); + // tell RabbitMQ that messages need to be delivered + rabbitTemplate.setMandatory(true); + + if (returnCallback != null) { + rabbitTemplate.setReturnsCallback(returnCallback); + } else { + rabbitTemplate.setReturnsCallback( + returned -> log.error("Can't deliver message {}", returned.getMessage())); + } + return rabbitTemplate; } diff --git a/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/message/ObjectExportNotification.java b/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/message/ObjectExportNotification.java index 27356a282..c73989c2f 100644 --- a/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/message/ObjectExportNotification.java +++ b/dina-messaging/src/main/java/ca/gc/aafc/dina/messaging/message/ObjectExportNotification.java @@ -3,12 +3,16 @@ import java.util.UUID; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Data; import lombok.Getter; +import lombok.NoArgsConstructor; import ca.gc.aafc.dina.messaging.DinaMessage; @Builder @AllArgsConstructor +@Data +@NoArgsConstructor @Getter public class ObjectExportNotification implements DinaMessage { diff --git a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/ConsumerProducerIT.java b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/ConsumerProducerIT.java index 84a40fef9..8967ff03e 100644 --- a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/ConsumerProducerIT.java +++ b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/ConsumerProducerIT.java @@ -6,8 +6,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; @@ -31,7 +29,6 @@ "dina.messaging.isConsumer=true" } ) -@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) public class ConsumerProducerIT { public static final RabbitMQContainer rabbitMQContainer = new RabbitMQContainer("rabbitmq:3.8.20-management-alpine"); diff --git a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/ErrorHandlingProducerIT.java b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/ErrorHandlingProducerIT.java new file mode 100644 index 000000000..d5d187738 --- /dev/null +++ b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/ErrorHandlingProducerIT.java @@ -0,0 +1,91 @@ +package ca.gc.aafc.dina.messaging; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.amqp.core.ReturnedMessage; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.RabbitMQContainer; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest( + properties = { + "dina.messaging.isProducer=true", + "dina.messaging.isConsumer=false" + } +) +@Import(ErrorHandlingProducerIT.RabbitTemplateTestConfig.class) +public class ErrorHandlingProducerIT { + + public static final RabbitMQContainer rabbitMQContainer = new RabbitMQContainer("rabbitmq:3.8.20-management-alpine"); + + @Inject + private RabbitTemplateTestConfig rabbitTemplateTestConfig; + + @Inject + private RabbitTemplate rabbitTemplate; + + @BeforeAll + static void beforeAll() { + rabbitMQContainer.start(); + } + + @AfterAll + static void afterAll() { + rabbitMQContainer.stop(); + } + + @DynamicPropertySource + static void registerRabbitMQProperties(DynamicPropertyRegistry registry) { + registry.add("rabbitmq.host", rabbitMQContainer::getHost); + registry.add("rabbitmq.port", rabbitMQContainer::getAmqpPort); + registry.add("rabbitmq.username", rabbitMQContainer::getAdminUsername); + registry.add("rabbitmq.password", rabbitMQContainer::getAdminPassword); + } + + @Test + public void sendMessageToNonExistentQueue_receiverReceives() throws InterruptedException { + DinaTestMessage myMessage = new DinaTestMessage("test-message Queue non-existing"); + rabbitTemplate.convertAndSend("non-existing", myMessage); + + assertTrue(rabbitTemplateTestConfig.getLatch().await(1000, TimeUnit.MILLISECONDS)); + assertNotNull(rabbitTemplateTestConfig.getReturnedMessage()); + } + + @TestConfiguration + public static class RabbitTemplateTestConfig { + + private final CountDownLatch latch = new CountDownLatch(1); + private ReturnedMessage returnedMessage; + + public CountDownLatch getLatch() { + return latch; + } + + public ReturnedMessage getReturnedMessage() { + return returnedMessage; + } + + @Bean + public RabbitTemplate.ReturnsCallback returnCallback() { + return m -> { + returnedMessage = m; + latch.countDown(); + }; + } + } +} diff --git a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/MessagingTestApplication.java b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/MessagingTestApplication.java new file mode 100644 index 000000000..0445577e2 --- /dev/null +++ b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/MessagingTestApplication.java @@ -0,0 +1,8 @@ +package ca.gc.aafc.dina.messaging; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) +public class MessagingTestApplication { +} diff --git a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumer.java b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumer.java index 33d2957ea..48fdbc65e 100644 --- a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumer.java +++ b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumer.java @@ -4,11 +4,13 @@ import lombok.Getter; import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; import ca.gc.aafc.dina.messaging.DinaTestMessage; @Component +@ConditionalOnProperty(prefix = "dina.messaging", name = "isConsumer", havingValue = "true") public class RabbitMQTestConsumer implements RabbitMQMessageConsumer { @Getter diff --git a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumerQueue2.java b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumerQueue2.java index 55a52db98..0dbd071c3 100644 --- a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumerQueue2.java +++ b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/consumer/RabbitMQTestConsumerQueue2.java @@ -1,6 +1,7 @@ package ca.gc.aafc.dina.messaging.consumer; import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; import ca.gc.aafc.dina.messaging.DinaTestMessage; @@ -9,6 +10,7 @@ import lombok.Getter; @Component +@ConditionalOnProperty(prefix = "dina.messaging", name = "isConsumer", havingValue = "true") public class RabbitMQTestConsumerQueue2 implements RabbitMQMessageConsumer { @Getter diff --git a/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/message/ObjectExportNotificationIT.java b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/message/ObjectExportNotificationIT.java new file mode 100644 index 000000000..ec13d3fad --- /dev/null +++ b/dina-messaging/src/test/java/ca/gc/aafc/dina/messaging/message/ObjectExportNotificationIT.java @@ -0,0 +1,28 @@ +package ca.gc.aafc.dina.messaging.message; + +import java.util.UUID; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; + +import ca.gc.aafc.dina.testsupport.TestResourceHelper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ObjectExportNotificationIT { + + @Test + public void testSerDe() throws JsonProcessingException { + + ObjectExportNotification oen = ObjectExportNotification.builder() + .uuid(UUID.randomUUID()) + .username("user") + .toa("toa").build(); + + String asJson = TestResourceHelper.OBJECT_MAPPER.writeValueAsString(oen); + + ObjectExportNotification oen2 = TestResourceHelper.OBJECT_MAPPER.readValue(asJson, ObjectExportNotification.class); + assertEquals(oen, oen2); + } +} diff --git a/dina-search/pom.xml b/dina-search/pom.xml index 8cb2605fb..c1febdf00 100644 --- a/dina-search/pom.xml +++ b/dina-search/pom.xml @@ -8,7 +8,7 @@ io.github.aafc-bicoe dina-base-parent - 0.116 + 0.117 dina-search diff --git a/dina-test-support/pom.xml b/dina-test-support/pom.xml index 41f3081e5..164113a77 100644 --- a/dina-test-support/pom.xml +++ b/dina-test-support/pom.xml @@ -9,7 +9,7 @@ io.github.aafc-bicoe dina-base-parent - 0.116 + 0.117 dina-test-support diff --git a/dina-workbook/pom.xml b/dina-workbook/pom.xml index 0948ff9dd..666fc9c7e 100644 --- a/dina-workbook/pom.xml +++ b/dina-workbook/pom.xml @@ -8,7 +8,7 @@ io.github.aafc-bicoe dina-base-parent - 0.116 + 0.117 dina-workbook diff --git a/pom.xml b/pom.xml index d62c37278..dedf927e8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.aafc-bicoe dina-base-parent - 0.116 + 0.117 pom