Skip to content

Commit 4894a18

Browse files
committed
chore(dispatcher): create custom assertions
1 parent 573e8cc commit 4894a18

8 files changed

Lines changed: 205 additions & 85 deletions

File tree

hub/dispatcher/src/test/java/com/hubsante/hub/service/DispatcherTest.java

Lines changed: 23 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
import static com.hubsante.hub.testsupport.HubTestScaffolding.aHub;
2525
import static com.hubsante.hub.testsupport.MessageTestUtils.*;
2626
import static com.hubsante.hub.testsupport.MetricsUtils.*;
27+
import static com.hubsante.hub.testsupport.assertions.HubAssertions.assertThatMessageSentTo;
28+
import static com.hubsante.hub.testsupport.assertions.HubAssertions.assertThatMessagesSentTo;
29+
import static com.hubsante.hub.testsupport.assertions.HubAssertions.assertThatNoMessageSentTo;
2730
import static org.junit.jupiter.api.Assertions.*;
2831
import static org.mockito.ArgumentMatchers.any;
2932
import static org.mockito.ArgumentMatchers.anyString;
3033
import static org.mockito.ArgumentMatchers.eq;
3134
import static org.mockito.Mockito.*;
3235

33-
import com.fasterxml.jackson.core.JsonProcessingException;
3436
import com.fasterxml.jackson.databind.ObjectMapper;
3537
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
3638
import com.hubsante.hub.config.HubConfiguration;
@@ -45,7 +47,6 @@
4547
import com.hubsante.model.Validator;
4648
import com.hubsante.model.edxl.EdxlMessage;
4749
import com.hubsante.model.exception.ValidationException;
48-
import com.hubsante.model.report.Error;
4950
import com.hubsante.model.report.ErrorCode;
5051
import com.hubsante.model.technical.noreq.TechnicalNoreqWrapper;
5152
import io.micrometer.core.instrument.MeterRegistry;
@@ -236,9 +237,7 @@ public void cisuTranscodingFromHealthToCisuOnHealthVhost() throws IOException {
236237

237238
String expectedTargetExchangeName = "transfer_15-15_v2.1_to_15-nexsis_vactive";
238239

239-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
240-
Mockito.verify(rabbitTemplate, times(1))
241-
.send(eq(expectedTargetExchangeName), eq(SAMU_A_ROUTING_KEY), argument.capture());
240+
assertThatMessageSentTo(rabbitTemplate, expectedTargetExchangeName, SAMU_A_ROUTING_KEY);
242241
}
243242

244243
@Test
@@ -253,9 +252,7 @@ public void cisuTranscodingFromHealthToCisuOnNexsisVhost() throws IOException {
253252

254253
verifyNoConversion(conversionHandler);
255254

256-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
257-
Mockito.verify(rabbitTemplate, times(1))
258-
.send(eq(DISTRIBUTION_EXCHANGE), eq(SDIS_C_MESSAGE_QUEUE), argument.capture());
255+
assertThatMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, SDIS_C_MESSAGE_QUEUE);
259256
}
260257

261258
@Test
@@ -274,9 +271,7 @@ public void cisuTranscodingFromCisuToHealthOnNexsisVhost() throws IOException {
274271

275272
String expectedTargetExchangeName = "transfer_15-nexsis_vactive_to_15-15_v2.1";
276273

277-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
278-
Mockito.verify(rabbitTemplate, times(1))
279-
.send(eq(expectedTargetExchangeName), eq(FIRE_ROUTING_KEY), argument.capture());
274+
assertThatMessageSentTo(rabbitTemplate, expectedTargetExchangeName, FIRE_ROUTING_KEY);
280275
}
281276

282277
@Test
@@ -293,9 +288,7 @@ public void cisuTranscodingFromCisuToHealthOnHealthVhost() throws IOException {
293288

294289
verifyNoConversion(conversionHandler);
295290

296-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
297-
Mockito.verify(rabbitTemplate, times(1))
298-
.send(eq(DISTRIBUTION_EXCHANGE), eq(SAMU_V3_MESSAGE_QUEUE), argument.capture());
291+
assertThatMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, SAMU_V3_MESSAGE_QUEUE);
299292
}
300293

301294
@Test
@@ -336,12 +329,8 @@ public void shouldCallConversionServiceForCISUVersionConvertedMessagesFromSamu()
336329

337330
String expectedTargetExchangeName = "transfer_15-nexsis_v1.9_to_15-nexsis_vactive";
338331

339-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
340-
Mockito.verify(rabbitTemplate, times(1))
341-
.send(
342-
eq(expectedTargetExchangeName),
343-
eq(SAMU_V3_DIRECT_CISU_ROUTING_KEY),
344-
argument.capture());
332+
assertThatMessageSentTo(
333+
rabbitTemplate, expectedTargetExchangeName, SAMU_V3_DIRECT_CISU_ROUTING_KEY);
345334
}
346335

347336
@Test
@@ -362,9 +351,7 @@ public void shouldCallConversionServiceForCISUVersionConvertedMessagesFromNexsis
362351

363352
String expectedTargetExchangeName = "transfer_15-nexsis_vactive_to_15-nexsis_v1.9";
364353

365-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
366-
Mockito.verify(rabbitTemplate, times(1))
367-
.send(eq(expectedTargetExchangeName), eq(FIRE_ROUTING_KEY), argument.capture());
354+
assertThatMessageSentTo(rabbitTemplate, expectedTargetExchangeName, FIRE_ROUTING_KEY);
368355
}
369356

370357
@ParameterizedTest
@@ -378,9 +365,7 @@ public void shouldSendMessageToCurrentVhost(String vhost) throws IOException {
378365

379366
verifyNoConversion(conversionHandler);
380367

381-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
382-
Mockito.verify(rabbitTemplate, times(1))
383-
.send(eq(DISTRIBUTION_EXCHANGE), eq(SAMU_V3_MESSAGE_QUEUE), argument.capture());
368+
assertThatMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, SAMU_V3_MESSAGE_QUEUE);
384369
}
385370

386371
@Test
@@ -435,9 +420,7 @@ public void shouldThrowExpiredBeforeDispatchMessageException() throws IOExceptio
435420
ex.getCause(),
436421
"Cause should be ExpiredBeforeDispatchMessageException");
437422

438-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
439-
Mockito.verify(rabbitTemplate, times(1))
440-
.send(eq(DISTRIBUTION_EXCHANGE), eq(SAMU_A_INFO_QUEUE), argument.capture());
423+
assertThatMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, SAMU_A_INFO_QUEUE);
441424
}
442425

443426
@Test
@@ -677,9 +660,7 @@ public void transferToOtherVhost() throws IOException {
677660
verify(dispatcher, times(1)).sendToTransferExchange(anyString(), any(), any());
678661

679662
// the message must NOT have been published on the source target queue
680-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
681-
Mockito.verify(rabbitTemplate, times(0))
682-
.send(eq(DISTRIBUTION_EXCHANGE), eq(SAMU_B_MESSAGE_QUEUE), argument.capture());
663+
assertThatNoMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, SAMU_B_MESSAGE_QUEUE);
683664
}
684665

685666
@Test
@@ -871,20 +852,13 @@ private void assertErrorHasBeenSent(
871852
String infoQueueName,
872853
ErrorCode errorCode,
873854
String referencedDistributionId,
874-
String... errorCause)
875-
throws JsonProcessingException {
855+
String... errorCause) {
876856

877-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
878-
Mockito.verify(rabbitTemplate, times(1))
879-
.send(eq(DISTRIBUTION_EXCHANGE), eq(infoQueueName), argument.capture());
880-
881-
Error error = getErrorFromMessage(edxlHandler, argument.getValue());
882-
assertEquals(errorCode, error.getErrorCode());
883-
assertEquals(referencedDistributionId, error.getReferencedDistributionID());
884-
if (errorCause != null) {
885-
Arrays.stream(errorCause)
886-
.forEach(cause -> assertTrue(error.getErrorCause().contains(cause)));
887-
}
857+
assertThatMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, infoQueueName)
858+
.asError()
859+
.hasCode(errorCode)
860+
.references(referencedDistributionId)
861+
.hasCauseContaining(errorCause);
888862
}
889863

890864
@Test
@@ -1017,9 +991,7 @@ public void transferErrorToOtherVhost() throws IOException, ValidationException
1017991

1018992
assertEquals("Mock schema validation error", errorThrown.getCause().getMessage());
1019993

1020-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
1021-
Mockito.verify(rabbitTemplate, times(1))
1022-
.send(eq(exchangeName), eq("fr.health.hub"), argument.capture());
994+
assertThatMessageSentTo(rabbitTemplate, exchangeName, "fr.health.hub");
1023995
}
1024996

1025997
@Test
@@ -1029,9 +1001,7 @@ public void sendErrorMessageToSameVhost() throws IOException {
10291001

10301002
dispatcher.dispatch(errorMessage);
10311003

1032-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
1033-
Mockito.verify(rabbitTemplate, times(1))
1034-
.send(eq(DISTRIBUTION_EXCHANGE), eq(SAMU_A_INFO_QUEUE), argument.capture());
1004+
assertThatMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, SAMU_A_INFO_QUEUE);
10351005
}
10361006

10371007
@Test
@@ -1084,9 +1054,7 @@ public void sendErrorMessageWhenErrorIsRaised() throws IOException, ValidationEx
10841054

10851055
assertEquals("Mock schema validation error", errorThrown.getCause().getMessage());
10861056

1087-
ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class);
1088-
Mockito.verify(rabbitTemplate, times(1))
1089-
.send(eq(DISTRIBUTION_EXCHANGE), eq(SAMU_A_INFO_QUEUE), argument.capture());
1057+
assertThatMessageSentTo(rabbitTemplate, DISTRIBUTION_EXCHANGE, SAMU_A_INFO_QUEUE);
10901058
}
10911059

10921060
@Test
@@ -1252,9 +1220,6 @@ public void shouldTransferEveryMessageReturnedByConverter() throws IOException {
12521220
verifyConversion(
12531221
conversionHandler, ConversionUtils.ConversionType.HEALTH_VERSION_CONVERSION);
12541222

1255-
ArgumentCaptor<Message> argCaptor = ArgumentCaptor.forClass(Message.class);
1256-
1257-
Mockito.verify(rabbitTemplate, times(2))
1258-
.send(eq(exchangeName), eq(SAMU_A_ROUTING_KEY), argCaptor.capture());
1223+
assertThatMessagesSentTo(rabbitTemplate, exchangeName, SAMU_A_ROUTING_KEY, 2);
12591224
}
12601225
}

hub/dispatcher/src/test/java/com/hubsante/hub/service/MessagePersistenceServiceTest.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
*/
1616
package com.hubsante.hub.service;
1717

18-
import static org.junit.jupiter.api.Assertions.assertThrows;
18+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1919
import static org.mockito.ArgumentMatchers.any;
2020
import static org.mockito.ArgumentMatchers.anyString;
2121
import static org.mockito.Mockito.*;
2222

2323
import com.fasterxml.jackson.core.type.TypeReference;
2424
import com.fasterxml.jackson.databind.ObjectMapper;
2525
import com.hubsante.hub.config.HubConfiguration;
26+
import com.hubsante.hub.exception.HubPersistenceException;
2627
import com.hubsante.hub.model.PersistedMessage;
2728
import com.hubsante.hub.repository.PersistedMessageRepository;
2829
import com.hubsante.hub.utils.EdxlUtils;
@@ -131,7 +132,9 @@ void shouldThrowWhenRepositoryFails() throws Exception {
131132
.thenReturn(Map.of());
132133
doThrow(new RuntimeException("MongoDB unavailable")).when(repository).save(any());
133134

134-
assertThrows(RuntimeException.class, () -> service.persist(edxlMessage));
135+
assertThatThrownBy(() -> service.persist(edxlMessage))
136+
.isInstanceOf(HubPersistenceException.class)
137+
.hasMessageContaining("MongoDB unavailable");
135138

136139
// save() was attempted but failed
137140
verify(repository, times(1)).save(any());
@@ -149,7 +152,9 @@ void shouldThrowWhenSerializationFails() throws Exception {
149152
when(edxlHandler.serializeJsonEDXL(any()))
150153
.thenThrow(new RuntimeException("Serialization error"));
151154

152-
assertThrows(RuntimeException.class, () -> service.persist(edxlMessage));
155+
assertThatThrownBy(() -> service.persist(edxlMessage))
156+
.isInstanceOf(HubPersistenceException.class)
157+
.hasMessageContaining("Serialization error");
153158

154159
// save() was never called because serialization failed before reaching it
155160
verify(repository, never()).save(any());

hub/dispatcher/src/test/java/com/hubsante/hub/service/TopologyRegistryTest.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
*/
1616
package com.hubsante.hub.service;
1717

18+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1819
import static org.junit.jupiter.api.Assertions.assertEquals;
1920
import static org.junit.jupiter.api.Assertions.assertNull;
20-
import static org.junit.jupiter.api.Assertions.assertThrows;
2121

22+
import com.hubsante.hub.config.Constants;
2223
import com.hubsante.hub.exception.ClientConfigurationException;
2324
import org.junit.jupiter.api.DisplayName;
2425
import org.junit.jupiter.api.Test;
@@ -46,7 +47,9 @@ void shouldLoadTopologyConfiguration() {
4647
void shouldThrowWhenTopologyBlockMissing() {
4748
Resource resource = new ClassPathResource("config/invalid-clients-no-perimeters.yaml");
4849

49-
assertThrows(ClientConfigurationException.class, () -> new TopologyRegistry(resource));
50+
assertThatThrownBy(() -> new TopologyRegistry(resource))
51+
.isInstanceOf(ClientConfigurationException.class)
52+
.hasMessageContaining("majorModelVersionPerVhost");
5053
}
5154

5255
@Test
@@ -55,6 +58,8 @@ void shouldThrowWhenFirePartnerMissing() {
5558
Resource resource =
5659
new ClassPathResource("config/invalid-clients-missing-fire-partner.yaml");
5760

58-
assertThrows(ClientConfigurationException.class, () -> new TopologyRegistry(resource));
61+
assertThatThrownBy(() -> new TopologyRegistry(resource))
62+
.isInstanceOf(ClientConfigurationException.class)
63+
.hasMessageContaining(Constants.NEXSIS_HUBEX_PARTNER);
5964
}
6065
}

hub/dispatcher/src/test/java/com/hubsante/hub/testsupport/MessageTestUtils.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
import com.fasterxml.jackson.core.JsonProcessingException;
2121
import com.hubsante.model.EdxlHandler;
2222
import com.hubsante.model.edxl.EdxlMessage;
23-
import com.hubsante.model.report.Error;
24-
import com.hubsante.model.report.ErrorWrapper;
2523
import java.io.IOException;
2624
import java.io.InputStream;
2725
import java.nio.charset.StandardCharsets;
@@ -174,23 +172,6 @@ public static String getContentTypeFromFilename(String filename) {
174172
}
175173
}
176174

177-
public static Error getErrorFromMessage(EdxlHandler edxlHandler, Message message)
178-
throws JsonProcessingException {
179-
180-
String msgString = new String(message.getBody());
181-
182-
ErrorWrapper wrapper =
183-
message.getMessageProperties()
184-
.getContentType()
185-
.equals(MessageProperties.CONTENT_TYPE_XML)
186-
? (ErrorWrapper)
187-
edxlHandler.deserializeXmlEDXL(msgString).getFirstContentMessage()
188-
: (ErrorWrapper)
189-
edxlHandler.deserializeJsonEDXL(msgString).getFirstContentMessage();
190-
191-
return wrapper.getError();
192-
}
193-
194175
public static void setCustomExpirationDate(EdxlMessage edxlMessage, long offset_in_seconds) {
195176
OffsetDateTime now = OffsetDateTime.now();
196177
edxlMessage.setDateTimeSent(now);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Copyright © 2023-2026 Agence du Numerique en Sante (ANS)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.hubsante.hub.testsupport.assertions;
17+
18+
import com.hubsante.model.report.Error;
19+
import com.hubsante.model.report.ErrorCode;
20+
import org.assertj.core.api.AbstractAssert;
21+
import org.assertj.core.api.Assertions;
22+
23+
public class ErrorAssert extends AbstractAssert<ErrorAssert, Error> {
24+
25+
ErrorAssert(Error actual) {
26+
super(actual, ErrorAssert.class);
27+
}
28+
29+
public ErrorAssert hasCode(ErrorCode expected) {
30+
isNotNull();
31+
Assertions.assertThat(actual.getErrorCode()).as("error code").isEqualTo(expected);
32+
return this;
33+
}
34+
35+
public ErrorAssert references(String expectedDistributionId) {
36+
isNotNull();
37+
Assertions.assertThat(actual.getReferencedDistributionID())
38+
.as("referenced distributionID of the %s error", actual.getErrorCode())
39+
.isEqualTo(expectedDistributionId);
40+
return this;
41+
}
42+
43+
public ErrorAssert hasCauseContaining(String... fragments) {
44+
isNotNull();
45+
Assertions.assertThat(actual.getErrorCause())
46+
.as("error cause of the %s error", actual.getErrorCode())
47+
.contains(fragments);
48+
return this;
49+
}
50+
}

0 commit comments

Comments
 (0)