From a750deaa7ca859be7fb982e4a9a0fda4027fa775 Mon Sep 17 00:00:00 2001 From: Jan Zickermann <jan.zickermann@dataport.de> Date: Thu, 13 Feb 2025 11:02:52 +0100 Subject: [PATCH] OZG-4097 send-attachment: Rethrow restclientresponse exception --- .../transfer/PostfachApiFacadeService.java | 62 +++- .../PostfachApiFacadeServiceTest.java | 293 +++++++++++++++++- 2 files changed, 332 insertions(+), 23 deletions(-) diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java index f40594d..1e24151 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeService.java @@ -6,10 +6,12 @@ import java.util.List; import java.util.UUID; import org.springframework.core.io.AbstractResource; +import org.springframework.web.client.RestClientResponseException; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.ServiceIfOsi2Enabled; import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.MessageExchangeApi; import de.ozgcloud.nachrichten.postfach.osiv2.gen.api.QuarantineApi; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; @@ -29,6 +31,14 @@ public class PostfachApiFacadeService { private final Osi2PostfachProperties.ApiConfiguration apiConfiguration; public void sendMessage(PostfachNachricht nachricht, List<Osi2FileUpload> attachments) { + try { + sendMessageRaw(nachricht, attachments); + } catch (RestClientResponseException e) { + throw new Osi2RuntimeException("sendMessage failed!", e); + } + } + + void sendMessageRaw(PostfachNachricht nachricht, List<Osi2FileUpload> attachments) { messageExchangeApi.sendMessage( requestMapper.mapMailboxId(nachricht), requestMapper.mapOutSendMessageRequestV2(nachricht, attachments) @@ -36,32 +46,72 @@ public class PostfachApiFacadeService { } public <T extends AbstractResource> void uploadChunk(FileChunkInfo chunkInfo, T chunkResource) { - quarantineApi.uploadChunk( - requestMapper.mapDomainChunkMetaData(chunkInfo), - apiConfiguration.getTenant(), - apiConfiguration.getNameIdentifier(), - chunkResource - ); + try { + uploadChunkRaw(chunkInfo, chunkResource); + } catch (RestClientResponseException e) { + throw new Osi2RuntimeException("uploadChunk failed!", e); + } + } + + <T extends AbstractResource> void uploadChunkRaw(FileChunkInfo chunkInfo, T chunkResource) { + quarantineApi.uploadChunk( + requestMapper.mapDomainChunkMetaData(chunkInfo), + apiConfiguration.getTenant(), + apiConfiguration.getNameIdentifier(), + chunkResource + ); } public boolean checkUploadSuccessful(final String messageId) { + try { + return checkUploadSuccessfulRaw(messageId); + } catch (RestClientResponseException e) { + throw new Osi2RuntimeException("checkUploadSuccessful failed!", e); + } + } + + boolean checkUploadSuccessfulRaw(final String messageId) { return responseMapper.isSafe( quarantineApi.getUploadStatus(UUID.fromString(messageId)) ); } public List<String> fetchPendingMessageIds() { + try { + return fetchPendingMessageIdsRaw(); + } catch (RestClientResponseException e) { + throw new Osi2RuntimeException("fetchPendingMessageIds failed!", e); + } + } + + List<String> fetchPendingMessageIdsRaw() { return responseMapper.toMessageIds( messageExchangeApi.receiveMessages(MAX_NUMBER_RECEIVED_MESSAGES, 0) ); } public PostfachNachricht fetchMessageById(final String messageId) { + try { + return fetchMessageByIdRaw(messageId); + } catch (RestClientResponseException e) { + throw new Osi2RuntimeException("fetchMessageById failed!", e); + } + } + + PostfachNachricht fetchMessageByIdRaw(final String messageId) { var messageReply = messageExchangeApi.getMessage(UUID.fromString(messageId)); return responseMapper.toPostfachNachricht(messageReply); } public void deleteMessage(final String messageId) { + try { + deleteMessageRaw(messageId); + } catch (RestClientResponseException e) { + throw new Osi2RuntimeException("deleteMessage failed!", e); + } + } + + void deleteMessageRaw(final String messageId) { messageExchangeApi.deleteMessage(UUID.fromString(messageId)); } } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java index 2ce7a47..97fc19a 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/PostfachApiFacadeServiceTest.java @@ -16,9 +16,11 @@ import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; +import org.springframework.web.client.RestClientResponseException; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.osiv2.config.Osi2PostfachProperties; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; import de.ozgcloud.nachrichten.postfach.osiv2.factory.FileChunkInfoTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; @@ -39,7 +41,7 @@ class PostfachApiFacadeServiceTest { @InjectMocks @Spy - PostfachApiFacadeService postfachApiFacadeService; + PostfachApiFacadeService service; @Mock MessageExchangeApi messageExchangeApi; @@ -59,6 +61,46 @@ class PostfachApiFacadeServiceTest { @DisplayName("send message") @Nested class TestSendMessage { + private final List<Osi2FileUpload> files = List.of(Osi2FileUploadTestFactory.create()); + + private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + + @DisplayName("without exception") + @Nested + class TestWithoutException { + + @DisplayName("should call sendMessage") + @Test + void shouldCallSendMessage() { + doNothing().when(service).sendMessageRaw(any(), any()); + + service.sendMessage(nachricht, files); + + verify(service).sendMessageRaw(nachricht, files); + } + } + + @DisplayName("with restclient response exception") + @Nested + class TestWithRestclientResponseException { + @Mock + RestClientResponseException restClientResponseException; + + @DisplayName("should rethrow as osi2 runtime exception") + @Test + void shouldRethrowAsOsi2RuntimeException() { + doThrow(restClientResponseException).when(service).sendMessageRaw(any(), any()); + + assertThatThrownBy(() -> service.sendMessage(nachricht, files)) + .isInstanceOf(Osi2RuntimeException.class) + .hasCause(restClientResponseException); + } + } + } + + @DisplayName("send message raw") + @Nested + class TestSendMessageRaw { @Mock OutSendMessageRequestV2 outSendMessageRequestV2; @@ -72,23 +114,76 @@ class PostfachApiFacadeServiceTest { @BeforeEach void mock() { - when(osi2RequestMapper.mapMailboxId(nachricht)).thenReturn(MAILBOX_ID); - when(osi2RequestMapper.mapOutSendMessageRequestV2(nachricht, files)).thenReturn(outSendMessageRequestV2); + when(osi2RequestMapper.mapMailboxId(any())).thenReturn(MAILBOX_ID); + when(osi2RequestMapper.mapOutSendMessageRequestV2(any(), any())).thenReturn(outSendMessageRequestV2); when(messageExchangeApi.sendMessage(any(), any())).thenReturn(messageExchangeSendMessageResponse); } + @DisplayName("should call mapMailboxId") + @Test + void shouldCallMapMailboxId() { + service.sendMessageRaw(nachricht, files); + + verify(osi2RequestMapper).mapMailboxId(nachricht); + } + + @DisplayName("should call mapOutSendMessageRequestV2") + @Test + void shouldCallMapOutSendMessageRequestV2() { + service.sendMessageRaw(nachricht, files); + + verify(osi2RequestMapper).mapOutSendMessageRequestV2(nachricht, files); + } + @DisplayName("should call sendMessage") @Test void shouldCallSendMessage() { - postfachApiFacadeService.sendMessage(nachricht, files); + service.sendMessageRaw(nachricht, files); verify(messageExchangeApi).sendMessage(MAILBOX_ID, outSendMessageRequestV2); } + } @DisplayName("fetch pending message ids") @Nested class TestFetchPendingMessageIds { + @DisplayName("without exception") + @Nested + class TestWithoutException { + + @DisplayName("should return fetchPendingMessageIdsRaw") + @Test + void shouldReturnFetchPendingMessageIdsRaw() { + doReturn(List.of(MESSAGE_ID_1, MESSAGE_ID_2)).when(service).fetchPendingMessageIdsRaw(); + + var result = service.fetchPendingMessageIds(); + + assertThat(result).containsExactly(MESSAGE_ID_1, MESSAGE_ID_2); + } + } + + @DisplayName("with restclient response exception") + @Nested + class TestWithRestclientResponseException { + @Mock + RestClientResponseException restClientResponseException; + + @DisplayName("should rethrow as osi2 runtime exception") + @Test + void shouldRethrowAsOsi2RuntimeException() { + doThrow(restClientResponseException).when(service).fetchPendingMessageIdsRaw(); + + assertThatThrownBy(() -> service.fetchPendingMessageIds()) + .isInstanceOf(Osi2RuntimeException.class) + .hasCause(restClientResponseException); + } + } + } + + @DisplayName("fetch pending message ids raw") + @Nested + class TestFetchPendingMessageIdsRaw { @DisplayName("with two pending messages") @Nested @@ -150,15 +245,64 @@ class PostfachApiFacadeServiceTest { } private List<String> fetchMessageIds() { - return postfachApiFacadeService.fetchPendingMessageIds(); + return service.fetchPendingMessageIds(); } } - @DisplayName("fetch Message by Id") + @DisplayName("fetch message by id") @Nested class TestFetchMessageById { + private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create(); + + @DisplayName("without exception") + @Nested + class TestWithoutException { + @BeforeEach + void mock() { + doReturn(nachricht).when(service).fetchMessageByIdRaw(MESSAGE_ID_1); + } + + @DisplayName("should call fetchMessageByIdRaw") + @Test + void shouldCallFetchMessageByIdRaw() { + service.fetchMessageById(MESSAGE_ID_1); + + verify(service).fetchMessageByIdRaw(MESSAGE_ID_1); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var result = service.fetchMessageById(MESSAGE_ID_1); + + assertThat(result).isEqualTo(nachricht); + } + } + + @DisplayName("with restclient response exception") + @Nested + class TestWithRestclientResponseException { + @Mock + RestClientResponseException restClientResponseException; + + @DisplayName("should rethrow as osi2 runtime exception") + @Test + void shouldRethrowAsOsi2RuntimeException() { + doThrow(restClientResponseException).when(service).fetchMessageByIdRaw(any()); + + assertThatThrownBy(() -> service.fetchMessageById(MESSAGE_ID_1)) + .isInstanceOf(Osi2RuntimeException.class) + .hasCause(restClientResponseException); + } + } + } + + @DisplayName("fetch Message by Id raw") + @Nested + class TestFetchMessageByIdRaw { + @Mock V1ReplyMessage replyMessage; @@ -166,7 +310,7 @@ class PostfachApiFacadeServiceTest { void shouldCallGetMessage() { when(messageExchangeApi.getMessage(any())).thenReturn(replyMessage); - postfachApiFacadeService.fetchMessageById(MESSAGE_ID_1); + service.fetchMessageByIdRaw(MESSAGE_ID_1); verify(messageExchangeApi).getMessage(any()); } @@ -176,7 +320,7 @@ class PostfachApiFacadeServiceTest { when(messageExchangeApi.getMessage(any())).thenReturn(replyMessage); when(osi2ResponseMapper.toPostfachNachricht(any())).thenReturn(PostfachNachrichtTestFactory.create()); - postfachApiFacadeService.fetchMessageById(MESSAGE_ID_1); + service.fetchMessageByIdRaw(MESSAGE_ID_1); verify(osi2ResponseMapper).toPostfachNachricht(any()); } @@ -186,7 +330,7 @@ class PostfachApiFacadeServiceTest { when(messageExchangeApi.getMessage(any())).thenReturn(replyMessage); when(osi2ResponseMapper.toPostfachNachricht(any())).thenReturn(PostfachNachrichtTestFactory.create()); - var postfachNachricht = postfachApiFacadeService.fetchMessageById(MESSAGE_ID_1); + var postfachNachricht = service.fetchMessageByIdRaw(MESSAGE_ID_1); assertThat(postfachNachricht).isInstanceOf(PostfachNachricht.class); } @@ -195,6 +339,43 @@ class PostfachApiFacadeServiceTest { @DisplayName("upload chunk") @Nested class TestUploadChunk { + + @Mock + FileChunkResource chunkResource; + + private final FileChunkInfo info = FileChunkInfoTestFactory.create(); + + @DisplayName("should call uploadChunkRaw") + @Test + void shouldCallUploadChunkRaw() { + doNothing().when(service).uploadChunkRaw(any(), any()); + + service.uploadChunk(info, chunkResource); + + verify(service).uploadChunkRaw(info, chunkResource); + } + + @DisplayName("with restclient response exception") + @Nested + class TestWithRestclientResponseException { + @Mock + RestClientResponseException restClientResponseException; + + @DisplayName("should rethrow as osi2 runtime exception") + @Test + void shouldRethrowAsOsi2RuntimeException() { + doThrow(restClientResponseException).when(service).uploadChunkRaw(any(), any()); + + assertThatThrownBy(() -> service.uploadChunk(info, chunkResource)) + .isInstanceOf(Osi2RuntimeException.class) + .hasCause(restClientResponseException); + } + } + } + + @DisplayName("upload chunk raw") + @Nested + class TestUploadChunkRaw { @Mock FileChunkResource chunkResource; @@ -216,7 +397,7 @@ class PostfachApiFacadeServiceTest { @DisplayName("should call mapDomainChunkMetadata") @Test void shouldCallMapDomainChunkMetadata() { - postfachApiFacadeService.uploadChunk(info, chunkResource); + service.uploadChunkRaw(info, chunkResource); verify(osi2RequestMapper).mapDomainChunkMetaData(info); } @@ -224,7 +405,7 @@ class PostfachApiFacadeServiceTest { @DisplayName("should call uploadChunk") @Test void shouldCallUploadChunk() { - postfachApiFacadeService.uploadChunk(info, chunkResource); + service.uploadChunkRaw(info, chunkResource); verify(quarantineApi).uploadChunk(domainChunkMetaData, TENANT, NAME_IDENTIFIER, chunkResource); } @@ -234,6 +415,52 @@ class PostfachApiFacadeServiceTest { @Nested class TestCheckUploadSuccessful { + @DisplayName("without exception") + @Nested + class TestWithoutException { + @BeforeEach + void mock() { + doReturn(true).when(service).checkUploadSuccessfulRaw(any()); + } + + @DisplayName("should call checkUploadSuccessfulRaw") + @Test + void shouldCallCheckUploadSuccessfulRaw() { + service.checkUploadSuccessful(MESSAGE_ID_1); + + verify(service).checkUploadSuccessfulRaw(MESSAGE_ID_1); + } + + @DisplayName("should return") + @Test + void shouldReturn() { + var result = service.checkUploadSuccessful(MESSAGE_ID_1); + + assertThat(result).isTrue(); + } + } + + @DisplayName("with restclient response exception") + @Nested + class TestWithRestclientResponseException { + @Mock + RestClientResponseException restClientResponseException; + + @DisplayName("should rethrow as osi2 runtime exception") + @Test + void shouldRethrowAsOsi2RuntimeException() { + doThrow(restClientResponseException).when(service).checkUploadSuccessfulRaw(any()); + + assertThatThrownBy(() -> service.checkUploadSuccessful(MESSAGE_ID_1)) + .isInstanceOf(Osi2RuntimeException.class) + .hasCause(restClientResponseException); + } + } + } + + @DisplayName("check upload successful raw") + @Nested + class TestCheckUploadSuccessfulRaw { private final QuarantineStatus uploadStatus = QuarantineStatus.SAFE; @@ -246,7 +473,7 @@ class PostfachApiFacadeServiceTest { @DisplayName("should call getUploadStatus") @Test void shouldCallGetUploadStatus() { - postfachApiFacadeService.checkUploadSuccessful(MESSAGE_ID_1); + service.checkUploadSuccessfulRaw(MESSAGE_ID_1); verify(quarantineApi).getUploadStatus(UUID.fromString(MESSAGE_ID_1)); } @@ -254,7 +481,7 @@ class PostfachApiFacadeServiceTest { @DisplayName("should call isSafe") @Test void shouldCallIsSafe() { - postfachApiFacadeService.checkUploadSuccessful(MESSAGE_ID_1); + service.checkUploadSuccessfulRaw(MESSAGE_ID_1); verify(osi2ResponseMapper).isSafe(uploadStatus); } @@ -262,16 +489,48 @@ class PostfachApiFacadeServiceTest { @DisplayName("should return true") @Test void shouldReturnTrue() { - var result = postfachApiFacadeService.checkUploadSuccessful(MESSAGE_ID_1); + var result = service.checkUploadSuccessfulRaw(MESSAGE_ID_1); assertThat(result).isTrue(); } } - @DisplayName("Delete Message") + @DisplayName("delete message") @Nested class TestDeleteMessage { + + @DisplayName("should call deleteMessage") + @Test + void shouldCallDeleteMessage() { + doNothing().when(service).deleteMessageRaw(any()); + + service.deleteMessage(MESSAGE_ID_1); + + verify(service).deleteMessageRaw(MESSAGE_ID_1); + } + + @DisplayName("with restclient response exception") + @Nested + class TestWithRestclientResponseException { + @Mock + RestClientResponseException restClientResponseException; + + @DisplayName("should rethrow as osi2 runtime exception") + @Test + void shouldRethrowAsOsi2RuntimeException() { + doThrow(restClientResponseException).when(service).deleteMessageRaw(any()); + + assertThatThrownBy(() -> service.deleteMessage(MESSAGE_ID_1)) + .isInstanceOf(Osi2RuntimeException.class) + .hasCause(restClientResponseException); + } + } + } + + @DisplayName("Delete Message raw") + @Nested + class TestDeleteMessageRaw { @Mock MessageExchangeDeleteMessageResponse replyMessage; @@ -279,9 +538,9 @@ class PostfachApiFacadeServiceTest { void shouldCallDeleteMessage() { when(messageExchangeApi.deleteMessage(any())).thenReturn(replyMessage); - postfachApiFacadeService.deleteMessage(UUID.randomUUID().toString()); + service.deleteMessage(MESSAGE_ID_1); - verify(messageExchangeApi).deleteMessage(any()); + verify(messageExchangeApi).deleteMessage(UUID.fromString(MESSAGE_ID_1)); } } -- GitLab