diff --git a/pom.xml b/pom.xml index 0130dea34cb3a0f7b1db4a66ea7785cb45546774..57d54c077f1d83562d58f388d5c81d7ab644ffbd 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,11 @@ <artifactId>nachrichten-manager-postfach-interface</artifactId> <version>${nachrichten-manager.version}</version> </dependency> + <dependency> + <groupId>de.ozgcloud.nachrichten</groupId> + <artifactId>nachrichten-manager-server</artifactId> + <version>${nachrichten-manager.version}</version> + </dependency> <dependency> <groupId>org.springframework.boot</groupId> diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachException.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachException.java deleted file mode 100644 index f5187621d37cc7b48e47a1884e0df775636fca86..0000000000000000000000000000000000000000 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachException.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.ozgcloud.nachrichten.postfach.osiv2; - -import de.ozgcloud.common.errorhandling.TechnicalException; - -public class OsiPostfachException extends TechnicalException { - public OsiPostfachException(String msg, Throwable cause) { - super(msg, cause); - } -} diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java index c0c1f70a570be4dd12c3c0b9ecfea8af87ea746b..8d34d7d340ea2e3c2306864e395551e2a7b9c43b 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteService.java @@ -4,6 +4,7 @@ import java.util.stream.Stream; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; import de.ozgcloud.nachrichten.postfach.PostfachRemoteService; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2ExceptionHandler; import de.ozgcloud.nachrichten.postfach.osiv2.transfer.Osi2PostfachService; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -13,6 +14,7 @@ import lombok.extern.log4j.Log4j2; @RequiredArgsConstructor public class OsiPostfachRemoteService implements PostfachRemoteService { private final Osi2PostfachService osi2PostfachService; + private final Osi2ExceptionHandler exceptionHandler; public static final String POSTFACH_TYPE_OSI = "OSI"; @@ -21,7 +23,7 @@ public class OsiPostfachRemoteService implements PostfachRemoteService { try { osi2PostfachService.sendMessage(nachricht); } catch (RuntimeException e) { - throw new OsiPostfachException("Failed to send message", e); + throw exceptionHandler.derivePostfachException(e); } } @@ -30,7 +32,7 @@ public class OsiPostfachRemoteService implements PostfachRemoteService { try { return osi2PostfachService.receiveMessages(); } catch (RuntimeException e) { - throw new OsiPostfachException("Failed to get messages", e); + throw exceptionHandler.derivePostfachException(e); } } @@ -39,7 +41,7 @@ public class OsiPostfachRemoteService implements PostfachRemoteService { try { osi2PostfachService.deleteMessage(messageId); } catch (RuntimeException e) { - throw new OsiPostfachException("Failed to delete message", e); + throw exceptionHandler.derivePostfachException(e); } } diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandler.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..db9c4f0c44c82dcbd1131ceaf32a2e6ec7221ca7 --- /dev/null +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandler.java @@ -0,0 +1,45 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.exception; + +import java.io.IOException; + +import jakarta.annotation.Nullable; + +import org.springframework.web.client.RestClientResponseException; + +import de.ozgcloud.nachrichten.postfach.PostfachMessageCode; +import de.ozgcloud.nachrichten.postfach.osiv2.ServiceIfOsi2Enabled; + +@ServiceIfOsi2Enabled +public class Osi2ExceptionHandler { + + static final String UNEXPECTED_ERROR_MESSAGE = "An unexpected error occurred. Please report this to the osiv2-postfach maintainers."; + + public Osi2PostfachException derivePostfachException(RuntimeException exception) { + if (exception instanceof Osi2RuntimeException osi2RuntimeException) { + return derivePostfachExceptionFromOsi2PostfachException(osi2RuntimeException); + } + return new Osi2PostfachException(UNEXPECTED_ERROR_MESSAGE, PostfachMessageCode.PROCESS_FAILED_MESSAGE_CODE, exception); + } + + Osi2PostfachException derivePostfachExceptionFromOsi2PostfachException(Osi2RuntimeException osi2RuntimeException) { + var cause = osi2RuntimeException.getCause(); + return new Osi2PostfachException(osi2RuntimeException.getMessage(), deriveMessageCode(cause), cause); + } + + PostfachMessageCode deriveMessageCode(@Nullable Throwable cause) { + if (cause instanceof RestClientResponseException restClientResponseException) { + return deriveMessageCodeFromRestClientResponseException(restClientResponseException); + } + // TODO KOP-3021 add message code for unsafe upload file + return PostfachMessageCode.PROCESS_FAILED_MESSAGE_CODE; + } + + PostfachMessageCode deriveMessageCodeFromRestClientResponseException(RestClientResponseException restClientResponseException) { + var cause = restClientResponseException.getCause(); + if (cause instanceof IOException) { + return PostfachMessageCode.SERVER_CONNECTION_FAILED_MESSAGE_CODE; + } + return PostfachMessageCode.PROCESS_FAILED_MESSAGE_CODE; + } + +} diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2PostfachException.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2PostfachException.java new file mode 100644 index 0000000000000000000000000000000000000000..1fae9a09afc9608a8a6f9943dbca0ec320cb1859 --- /dev/null +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2PostfachException.java @@ -0,0 +1,10 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.exception; + +import de.ozgcloud.nachrichten.postfach.PostfachException; +import de.ozgcloud.nachrichten.postfach.PostfachMessageCode; + +public class Osi2PostfachException extends PostfachException { + public Osi2PostfachException(String msg, PostfachMessageCode messageCode, Throwable cause) { + super(msg, messageCode, cause); + } +} diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2RuntimeException.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2RuntimeException.java new file mode 100644 index 0000000000000000000000000000000000000000..6f1966d63bfb58c42ac643afec10ca9c4ebb336b --- /dev/null +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2RuntimeException.java @@ -0,0 +1,12 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.exception; + +public class Osi2RuntimeException extends RuntimeException { + public Osi2RuntimeException(String msg) { + super(msg); + } + + public Osi2RuntimeException(String msg, Throwable cause) { + super(msg, cause); + } + +} diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2UploadException.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2UploadException.java new file mode 100644 index 0000000000000000000000000000000000000000..447a048689a9b31c489b88650536a9bfe828ebad --- /dev/null +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2UploadException.java @@ -0,0 +1,13 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.exception; + +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineStatus; + +public class Osi2UploadException extends RuntimeException { + public Osi2UploadException(QuarantineStatus uploadStatus) { + super(uploadStatus.toString()); + } + + public boolean isUnsafe() { + return QuarantineStatus.fromValue(getMessage()) == QuarantineStatus.UNSAFE; + } +} diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineService.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineService.java index df620a81491b55fd3a1d1f2ebca4e9f5fe976dc6..325c202b5483cc8a6ffdb4fb8ff72a52615d23b3 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineService.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineService.java @@ -15,8 +15,8 @@ import java.util.stream.LongStream; import java.util.stream.Stream; import de.ozgcloud.apilib.file.OzgCloudFile; -import de.ozgcloud.nachrichten.postfach.osiv2.OsiPostfachException; import de.ozgcloud.nachrichten.postfach.osiv2.ServiceIfOsi2Enabled; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2FileUpload; import de.ozgcloud.nachrichten.postfach.osiv2.storage.Osi2BinaryFileRemoteService; @@ -51,7 +51,7 @@ public class Osi2QuarantineService { try (var fileInputStream = binaryFileService.streamFileContent(file.getId().toString())) { return uploadInputStreamToQuarantine(file, fileInputStream); } catch (IOException e) { - throw new OsiPostfachException("Failed to close input stream!", e); + throw new Osi2RuntimeException("Failed to close input stream!", e); } } @@ -82,7 +82,6 @@ public class Osi2QuarantineService { synchronized boolean checkVirusScanCompleted(List<Osi2FileUpload> osi2FileMetadata) { - // TODO return true; } @@ -90,9 +89,12 @@ public class Osi2QuarantineService { try { waitUntil(() -> checkVirusScanCompleted(osi2FileMetadata), POLLING_INTERVAL, POLLING_TIMEOUT); } catch (ExecutionException e) { - throw new OsiPostfachException("Expect the scan to complete successfully!", e.getCause()); + if (e.getCause() instanceof Osi2RuntimeException osi2RuntimeException) { + throw osi2RuntimeException; + } + throw new IllegalStateException("Unexpected exception Expect the scan to complete successfully!", e.getCause()); } catch (TimeoutException e) { - throw new OsiPostfachException("Expect the scan to complete after %d seconds!".formatted(POLLING_TIMEOUT.getSeconds()), e); + throw new Osi2RuntimeException("Expect the scan to complete after %d seconds!".formatted(POLLING_TIMEOUT.getSeconds()), e); } catch (InterruptedException e) { LOG.debug("[waitForVirusScan] Interrupt"); Thread.currentThread().interrupt(); diff --git a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java index fbd75f8856267849a83265f973917c6e2f0b28c8..0a29139847121cca2a8394506998f5cf8208605e 100644 --- a/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java +++ b/src/main/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapper.java @@ -16,10 +16,12 @@ import org.mapstruct.ReportingPolicy; import de.ozgcloud.nachrichten.postfach.PostfachAddress; import de.ozgcloud.nachrichten.postfach.PostfachAddressIdentifier; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; -import de.ozgcloud.nachrichten.postfach.osiv2.OsiPostfachException; import de.ozgcloud.nachrichten.postfach.osiv2.OsiPostfachRemoteService; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2UploadException; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessage; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessagesResponse; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineStatus; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; import lombok.Builder; @@ -95,7 +97,7 @@ public interface Osi2ResponseMapper { default List<String> toMessageIds(MessageExchangeReceiveMessagesResponse response) { if (response == null) { - throw new OsiPostfachException("Expect non empty response!", null); + throw new Osi2RuntimeException("Expect non empty response!", null); } return Optional.ofNullable(response.getMessages()) @@ -107,6 +109,14 @@ public interface Osi2ResponseMapper { .toList(); } + default boolean isSafe(QuarantineStatus uploadStatus) { + return switch (uploadStatus) { + case NONE, UNSAFE, CORRUPT, MISSING -> throw new Osi2UploadException(uploadStatus); + case LEGACY, COMMITED -> false; + case SAFE -> true; + }; + } + @Builder @Getter class StringBasedIdentifier implements PostfachAddressIdentifier { 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 bd43b7de6be09deaf45a1a7fbb9cdc6254293c3b..f40594df2a6d9691567c076e4b12d3efce0b6fa7 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 @@ -44,6 +44,12 @@ public class PostfachApiFacadeService { ); } + public boolean checkUploadSuccessful(final String messageId) { + return responseMapper.isSafe( + quarantineApi.getUploadStatus(UUID.fromString(messageId)) + ); + } + public List<String> fetchPendingMessageIds() { return responseMapper.toMessageIds( messageExchangeApi.receiveMessages(MAX_NUMBER_RECEIVED_MESSAGES, 0) diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java index c21d0be38489cc11cb16dfe1484b57a4e3f7a4f9..6c95d87f8b300c0e7108738d7793a95be5475551 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/OsiPostfachRemoteServiceTest.java @@ -1,9 +1,9 @@ package de.ozgcloud.nachrichten.postfach.osiv2; +import static de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; -import java.util.UUID; import java.util.stream.Stream; import org.junit.jupiter.api.DisplayName; @@ -14,18 +14,23 @@ import org.mockito.Mock; import org.mockito.Spy; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2ExceptionHandler; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2PostfachException; import de.ozgcloud.nachrichten.postfach.osiv2.factory.PostfachNachrichtTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.transfer.Osi2PostfachService; class OsiPostfachRemoteServiceTest { - @Spy @InjectMocks + @Spy private OsiPostfachRemoteService osiPostfachRemoteService; @Mock private Osi2PostfachService osi2PostfachService; + @Mock + private Osi2ExceptionHandler exceptionHandler; + private final PostfachNachricht nachricht1 = PostfachNachrichtTestFactory.createBuilder() .subject("Nachricht 1") .build(); @@ -48,11 +53,15 @@ class OsiPostfachRemoteServiceTest { @DisplayName("should throw osi postfach exception on runtime exception") @Test void shouldThrowOsiPostfachExceptionOnRuntimeException() { - doThrow(new RuntimeException()).when(osi2PostfachService).sendMessage(nachricht1); + var runtimeException = createRuntimeException(); + var osi2PostfachException = createOsi2PostfachException(); + doThrow(runtimeException).when(osi2PostfachService).sendMessage(nachricht1); + when(exceptionHandler.derivePostfachException(runtimeException)).thenReturn(osi2PostfachException); assertThatThrownBy(() -> osiPostfachRemoteService.sendMessage(nachricht1)) - .isInstanceOf(OsiPostfachException.class); + .isEqualTo(osi2PostfachException); } + } @DisplayName("get all messages") @@ -68,6 +77,18 @@ class OsiPostfachRemoteServiceTest { assertThat(result).containsExactly(nachricht1, nachricht2); } + + @DisplayName("should throw osi postfach exception on runtime exception") + @Test + void shouldThrowOsiPostfachExceptionOnRuntimeException() { + var runtimeException = createRuntimeException(); + var osi2PostfachException = createOsi2PostfachException(); + doThrow(runtimeException).when(osi2PostfachService).receiveMessages(); + when(exceptionHandler.derivePostfachException(runtimeException)).thenReturn(osi2PostfachException); + + assertThatThrownBy(() -> osiPostfachRemoteService.getAllMessages()) + .isEqualTo(osi2PostfachException); + } } @DisplayName("delete message") @@ -77,17 +98,21 @@ class OsiPostfachRemoteServiceTest { @DisplayName("should call deleteMessage") @Test void shouldCallDeleteMessage() { - osi2PostfachService.deleteMessage(UUID.randomUUID().toString()); + osiPostfachRemoteService.deleteMessage(MESSAGE_ID_1); - verify(osi2PostfachService).deleteMessage(any()); + verify(osi2PostfachService).deleteMessage(MESSAGE_ID_1); } @DisplayName("should throw osi postfach exception on runtime exception") @Test void shouldThrowOsiPostfachExceptionOnRuntimeException() { - doThrow(new RuntimeException()).when(osi2PostfachService).deleteMessage(UUID.randomUUID().toString()); + var runtimeException = createRuntimeException(); + var osi2PostfachException = createOsi2PostfachException(); + doThrow(runtimeException).when(osi2PostfachService).deleteMessage(any()); + when(exceptionHandler.derivePostfachException(runtimeException)).thenReturn(osi2PostfachException); - assertThatThrownBy(() -> osiPostfachRemoteService.deleteMessage(anyString())).isInstanceOf(OsiPostfachException.class); + assertThatThrownBy(() -> osiPostfachRemoteService.deleteMessage(MESSAGE_ID_1)) + .isEqualTo(osi2PostfachException); } } @@ -114,4 +139,12 @@ class OsiPostfachRemoteServiceTest { assertThat(result).isTrue(); } } + + private RuntimeException createRuntimeException() { + return new RuntimeException(); + } + + private Osi2PostfachException createOsi2PostfachException() { + return new Osi2PostfachException("abc", null, null); + } } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandlerTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandlerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..446c19b95c74b43f245ad896cc253f2c41aefe7f --- /dev/null +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/exception/Osi2ExceptionHandlerTest.java @@ -0,0 +1,168 @@ +package de.ozgcloud.nachrichten.postfach.osiv2.exception; + +import static de.ozgcloud.nachrichten.postfach.PostfachMessageCode.*; +import static de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2ExceptionHandler.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.io.IOException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.web.client.RestClientResponseException; + +class Osi2ExceptionHandlerTest { + + @InjectMocks + @Spy + private Osi2ExceptionHandler handler; + + @DisplayName("derive postfach exception") + @Nested + class TestDerivePostfachException { + + @Mock + Osi2RuntimeException osi2RuntimeException; + + @Mock + Osi2PostfachException postfachException; + + @Mock + RuntimeException exception; + + @DisplayName("should derive postfach exception from osi2 postfach exception") + @Test + void shouldDerivePostfachExceptionFromOsi2PostfachException() { + doReturn(postfachException).when(handler).derivePostfachExceptionFromOsi2PostfachException(osi2RuntimeException); + + var result = handler.derivePostfachException(osi2RuntimeException); + + assertThat(result).isEqualTo(postfachException); + } + + + @DisplayName("should return unexpected error exception with message by default") + @Test + void shouldReturnUnexpectedErrorException() { + var result = handler.derivePostfachException(exception); + + assertThat(result.getMessage()).startsWith(UNEXPECTED_ERROR_MESSAGE); + } + + @DisplayName("should return unexpected error exception with cause by default") + @Test + void shouldReturnUnexpectedErrorExceptionWithCauseByDefault() { + var result = handler.derivePostfachException(exception); + + assertThat(result.getCause()).isEqualTo(exception); + } + } + + @DisplayName("derive postfach exception from osi2 postfach exception") + @Nested + class TestDerivePostfachExceptionFromOsi2PostfachException { + + private Osi2RuntimeException osi2RuntimeException; + + static final String TEST_MESSAGE = "test-message"; + + @Mock + RuntimeException cause; + + @BeforeEach + void mock() { + osi2RuntimeException = new Osi2RuntimeException(TEST_MESSAGE, cause); + doReturn(PROCESS_FAILED_MESSAGE_CODE).when(handler).deriveMessageCode(cause); + } + + @DisplayName("should return with message") + @Test + void shouldReturnWithMessage() { + var result = handler.derivePostfachExceptionFromOsi2PostfachException(osi2RuntimeException); + + assertThat(result.getMessage()).startsWith(TEST_MESSAGE); + } + + @DisplayName("should return with cause") + @Test + void shouldReturnWithCause() { + var result = handler.derivePostfachExceptionFromOsi2PostfachException(osi2RuntimeException); + + assertThat(result) + .extracting(Exception::getCause) + .isEqualTo(cause); + } + + @DisplayName("should return with message code") + @Test + void shouldReturnWithMessageCode() { + var result = handler.derivePostfachExceptionFromOsi2PostfachException(osi2RuntimeException); + + assertThat(result) + .extracting(Osi2PostfachException::getMessageCode) + .isEqualTo(PROCESS_FAILED_MESSAGE_CODE); + } + } + + @DisplayName("derive message code") + @Nested + class TestDeriveMessageCode { + @Mock + RestClientResponseException restClientResponseException; + + @DisplayName("should derive message code from rest client response exception") + @Test + void shouldDeriveMessageCodeFromRestClientResponseException() { + doReturn(SERVER_CONNECTION_FAILED_MESSAGE_CODE).when(handler) + .deriveMessageCodeFromRestClientResponseException(restClientResponseException); + + var result = handler.deriveMessageCode(restClientResponseException); + + assertThat(result).isEqualTo(SERVER_CONNECTION_FAILED_MESSAGE_CODE); + } + + @DisplayName("should return processed failed error code by default") + @Test + void shouldReturnProcessedFailedErrorCodeByDefault() { + var result = handler.deriveMessageCode(null); + + assertThat(result).isEqualTo(PROCESS_FAILED_MESSAGE_CODE); + } + } + + @DisplayName("derive message code from rest client response exception") + @Nested + class TestDeriveMessageCodeFromRestClientResponseException { + @Mock + IOException ioException; + + @Mock + private RestClientResponseException restClientResponseException; + + @DisplayName("should return server connection failed message code") + @Test + void shouldReturnServerConnectionFailedMessageCode() { + when(restClientResponseException.getCause()).thenReturn(ioException); + + var result = handler.deriveMessageCodeFromRestClientResponseException(restClientResponseException); + + assertThat(result).isEqualTo(SERVER_CONNECTION_FAILED_MESSAGE_CODE); + } + + @DisplayName("should return process failed message code by default") + @Test + void shouldReturnProcessFailedMessageCodeByDefault() { + when(restClientResponseException.getCause()).thenReturn(null); + + var result = handler.deriveMessageCodeFromRestClientResponseException(restClientResponseException); + + assertThat(result).isEqualTo(PROCESS_FAILED_MESSAGE_CODE); + } + } + +} \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java index a104cfc9d8ee0dc6d185b871a27103b7f9d55542..70525c804aa0c2d262f54afafcde661b6ebb4bc6 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/factory/MessageExchangeReceiveMessagesResponseTestFactory.java @@ -14,7 +14,7 @@ public class MessageExchangeReceiveMessagesResponseTestFactory { return new MessageExchangeReceiveMessagesResponse() .messages(Arrays.stream(uuids) .map(uuid -> MessageExchangeReceiveMessageTestFactory.create() - .guid(UUID.fromString(uuid))) + .guid(uuid == null ? null : UUID.fromString(uuid))) .toList()); } diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineServiceTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineServiceTest.java index 811d5e8d1d80a7cbb6a41e5ac107bb5edb2d8a62..df713f328d48b8e080d0d7fdd8292423ce6e6679 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineServiceTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2QuarantineServiceTest.java @@ -20,7 +20,8 @@ import org.mockito.Spy; import de.ozgcloud.apilib.file.OzgCloudFile; import de.ozgcloud.apilib.file.OzgCloudFileId; import de.ozgcloud.apilib.file.OzgCloudFileTestFactory; -import de.ozgcloud.nachrichten.postfach.osiv2.OsiPostfachException; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2PostfachException; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; import de.ozgcloud.nachrichten.postfach.osiv2.model.Osi2FileUpload; import de.ozgcloud.nachrichten.postfach.osiv2.storage.Osi2BinaryFileRemoteService; @@ -178,7 +179,7 @@ class Osi2QuarantineServiceTest { doThrow(new IOException("test")).when(fileInputStream).close(); assertThatThrownBy(this::uploadFileToQuarantine) - .isInstanceOf(OsiPostfachException.class); + .isInstanceOf(Osi2RuntimeException.class); } Osi2FileUpload uploadFileToQuarantine() { @@ -214,4 +215,10 @@ class Osi2QuarantineServiceTest { } } + @DisplayName("check virus scan completed") + @Nested + class TestCheckVirusScanCompleted { + + } + } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java index 8806cc719991a35cc7891a72b853542473eed084..1c82d188046d48ec8014f6324ee3dbade797d75f 100644 --- a/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java +++ b/src/test/java/de/ozgcloud/nachrichten/postfach/osiv2/transfer/Osi2ResponseMapperTest.java @@ -16,7 +16,11 @@ import org.mapstruct.factory.Mappers; import org.mockito.InjectMocks; import de.ozgcloud.nachrichten.postfach.PostfachNachricht; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2RuntimeException; +import de.ozgcloud.nachrichten.postfach.osiv2.exception.Osi2UploadException; +import de.ozgcloud.nachrichten.postfach.osiv2.factory.MessageExchangeReceiveMessagesResponseTestFactory; import de.ozgcloud.nachrichten.postfach.osiv2.factory.V1ReplyMessageTestFactory; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineStatus; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyBehavior; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; @@ -149,6 +153,78 @@ class Osi2ResponseMapperTest { private PostfachNachricht doMapping() { return mapper.toPostfachNachricht(message); } + } + + @DisplayName("to message ids") + @Nested + class TestToMessageIds { + + @DisplayName("should throw on null response") + @Test + void shouldThrowOnNullResponse() { + assertThatThrownBy(() -> mapper.toMessageIds(null)) + .isInstanceOf(Osi2RuntimeException.class); + } + + @DisplayName("should map empty response") + @Test + void shouldMapEmptyResponse() { + var response = MessageExchangeReceiveMessagesResponseTestFactory.create(); + + var result = mapper.toMessageIds(response); + + assertThat(result).isEmpty(); + } + + @DisplayName("should map message ids") + @Test + void shouldMapMessageIds() { + var response = MessageExchangeReceiveMessagesResponseTestFactory.create( + MessageExchangeReceiveMessagesResponseTestFactory.MESSAGE_ID_1, + null, + MessageExchangeReceiveMessagesResponseTestFactory.MESSAGE_ID_2 + ); + + var result = mapper.toMessageIds(response); + + assertThat(result).containsExactly( + MessageExchangeReceiveMessagesResponseTestFactory.MESSAGE_ID_1, + MessageExchangeReceiveMessagesResponseTestFactory.MESSAGE_ID_2 + ); + } + } + + @DisplayName("is safe") + @Nested + class TestIsSafe { + @DisplayName("should throw for bad end status") + @ParameterizedTest + @ValueSource(strings = { "None", "Unsafe", "Corrupt", "Missing" }) + void shouldThrowForBadEndStatus(String status) { + var uploadStatus = QuarantineStatus.fromValue(status); + + assertThatThrownBy(() -> mapper.isSafe(uploadStatus)) + .isInstanceOf(Osi2UploadException.class) + .hasMessage(status); + } + @DisplayName("should return false for unfinished status") + @ParameterizedTest + @ValueSource(strings = { "Legacy", "Commited" }) + void shouldReturnFalseForUnfinishedStatus(String status) { + var uploadStatus = QuarantineStatus.fromValue(status); + + var result = mapper.isSafe(uploadStatus); + + assertThat(result).isFalse(); + } + + @DisplayName("should return true for safe status") + @Test + void shouldReturnTrueForSafeStatus() { + var result = mapper.isSafe(QuarantineStatus.SAFE); + + assertThat(result).isTrue(); + } } } 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 a89ecc780e801000b07fed65195eca6127e15b4a..2ce7a47eb0f5b87b3ac4212b4418e8ef5998b52b 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 @@ -29,6 +29,7 @@ import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeDeleteMes import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeReceiveMessagesResponse; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.MessageExchangeSendMessageResponse; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.OutSendMessageRequestV2; +import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.QuarantineStatus; import de.ozgcloud.nachrichten.postfach.osiv2.gen.model.V1ReplyMessage; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkInfo; import de.ozgcloud.nachrichten.postfach.osiv2.model.FileChunkResource; @@ -229,6 +230,45 @@ class PostfachApiFacadeServiceTest { } } + @DisplayName("check upload successful") + @Nested + class TestCheckUploadSuccessful { + + + private final QuarantineStatus uploadStatus = QuarantineStatus.SAFE; + + @BeforeEach + void mock() { + when(osi2ResponseMapper.isSafe(any())).thenReturn(true); + when(quarantineApi.getUploadStatus(any())).thenReturn(uploadStatus); + } + + @DisplayName("should call getUploadStatus") + @Test + void shouldCallGetUploadStatus() { + postfachApiFacadeService.checkUploadSuccessful(MESSAGE_ID_1); + + verify(quarantineApi).getUploadStatus(UUID.fromString(MESSAGE_ID_1)); + } + + @DisplayName("should call isSafe") + @Test + void shouldCallIsSafe() { + postfachApiFacadeService.checkUploadSuccessful(MESSAGE_ID_1); + + verify(osi2ResponseMapper).isSafe(uploadStatus); + } + + @DisplayName("should return true") + @Test + void shouldReturnTrue() { + var result = postfachApiFacadeService.checkUploadSuccessful(MESSAGE_ID_1); + + assertThat(result).isTrue(); + } + + } + @DisplayName("Delete Message") @Nested class TestDeleteMessage {