diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/file/AttachmentFileService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/file/AttachmentFileService.java index d04fc89d20cd0b97c24febf77951b620788e66c5..a4ef01bb4e6c538a887d6b331001331df1dbb3e6 100644 --- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/file/AttachmentFileService.java +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/file/AttachmentFileService.java @@ -50,7 +50,7 @@ import de.ozgcloud.nachrichten.postfach.FileId; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; -@Service(NachrichtenManagerConfiguration.ATTACHMENT_FILE_SERVICE_NAME) +@Service(NachrichtenManagerConfiguration.ATTACHMENT_FILE_SERVICE_NAME) // NOSONAR @RequiredArgsConstructor @Log4j2 public class AttachmentFileService { @@ -58,10 +58,10 @@ public class AttachmentFileService { private static final int BUFFER_SIZE = 4 * 1024; static final String ATTACHMENT_NAME = "PostfachAttachment"; - @Qualifier(NachrichtenManagerConfiguration.OZG_CLOUD_FILE_SERVICE_NAME) + @Qualifier(NachrichtenManagerConfiguration.OZG_CLOUD_FILE_SERVICE_NAME) // NOSONAR private final OzgCloudFileService ozgCloudFileService; private final OzgCloudFileIdMapper fileIdMapper; - @Qualifier(NachrichtenManagerConfiguration.ATTACHMENT_FILE_MAPPER_NAME) + @Qualifier(NachrichtenManagerConfiguration.ATTACHMENT_FILE_MAPPER_NAME) // NOSONAR private final AttachmentFileMapper attachmentFileMapper; private final TaskExecutor taskExecutor; @@ -92,20 +92,22 @@ public class AttachmentFileService { } } - public String createAttachmentFile(AttachmentFile attachmentFile, String fileContent) { - var ozgCloudFileId = ozgCloudFileService.uploadFile(attachmentFileMapper.toOzgCloudUploadFile(enhanceAttachmentFile(attachmentFile, fileContent)), - toDecodedInputStream(fileContent)); + public String uploadAttachmentFile(AttachmentFile attachmentFile, String fileContent) { + var decodedContent = Base64.getDecoder().decode(fileContent); + var ozgCloudFileId = ozgCloudFileService.uploadFile(attachmentFileMapper.toOzgCloudUploadFile( + addContentTypeIfMissing(attachmentFile, decodedContent)), + toInputStream(decodedContent)); return ozgCloudFileId.toString(); } - AttachmentFile enhanceAttachmentFile(AttachmentFile attachmentFile, String fileContent) { + AttachmentFile addContentTypeIfMissing(AttachmentFile attachmentFile, byte[] fileContent) { if (StringUtils.isBlank(attachmentFile.getContentType())) { return attachmentFile.toBuilder().contentType(getContentType(attachmentFile, fileContent)).build(); } return attachmentFile; } - String getContentType(AttachmentFile attachmentFile, String fileContent) { + String getContentType(AttachmentFile attachmentFile, byte[] fileContent) { return getTypeByFileName(attachmentFile).or(() -> getTypeByContent(fileContent)).orElseGet(() -> getByMimeTypes(attachmentFile)); } @@ -114,7 +116,7 @@ public class AttachmentFileService { return Optional.ofNullable(contentType); } - Optional<String> getTypeByContent(String fileContent) { + Optional<String> getTypeByContent(byte[] fileContent) { try (var contentStream = toInputStream(fileContent)) { return Optional.ofNullable(URLConnection.guessContentTypeFromStream(contentStream)); } catch (IOException e) { @@ -127,11 +129,7 @@ public class AttachmentFileService { return mimetypesFileTypeMap.getContentType(attachmentFile.getName()); } - InputStream toDecodedInputStream(String content) { - return new ByteArrayInputStream(Base64.getDecoder().decode(content)); - } - - InputStream toInputStream(String content) { - return IOUtils.toInputStream(content, Charset.defaultCharset()); + InputStream toInputStream(byte[] content) { + return new ByteArrayInputStream(content); } } diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentService.java index 9d04ee4ea72afc3555c3c98d467902ffcc9e6997..47dd7b5c7815121bd4b762ed0ae776dd0bd1967e 100644 --- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentService.java +++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentService.java @@ -69,7 +69,7 @@ public class MessageAttachmentService { } public String persistAttachment(String vorgangId, MessageAttachment attachment) { - return attachmentFileService.createAttachmentFile(buildAttachmentFile(vorgangId, attachment), attachment.getContent()); + return attachmentFileService.uploadAttachmentFile(buildAttachmentFile(vorgangId, attachment), attachment.getContent()); } AttachmentFile buildAttachmentFile(String vorgangId, MessageAttachment attachment) { diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/file/AttachmentFileServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/file/AttachmentFileServiceTest.java index 972a5e900e991c1aea4c6ed229af59d107ca8988..f7c3bbea286b0193ee61b1a88cd5c5a8df85ba0d 100644 --- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/file/AttachmentFileServiceTest.java +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/file/AttachmentFileServiceTest.java @@ -57,12 +57,14 @@ import de.ozgcloud.apilib.file.OzgCloudFileId; import de.ozgcloud.apilib.file.OzgCloudFileService; import de.ozgcloud.apilib.file.OzgCloudUploadFile; import de.ozgcloud.apilib.vorgang.OzgCloudFileIdMapper; +import de.ozgcloud.common.test.TestUtils; import de.ozgcloud.nachrichten.postfach.FileId; +import lombok.SneakyThrows; class AttachmentFileServiceTest { private static final String FILE_ID = UUID.randomUUID().toString(); - private static final String FILE_CONTENT = LoremIpsum.getInstance().getWords(1); + private static final byte[] FILE_CONTENT = LoremIpsum.getInstance().getWords(1).getBytes(); @Spy @InjectMocks @@ -191,9 +193,27 @@ class AttachmentFileServiceTest { } @Nested - class TestCreateAttachmentFile { + class TestConnectToOutputStream { + + @SneakyThrows + @Test + void shouldReturnOutputStream() { + try (var inputStream = new PipedInputStream()) { + + var result = service.connectToOutputStream(inputStream); + result.write(FILE_CONTENT); + result.close(); + + assertThat(inputStream).hasBinaryContent(FILE_CONTENT); + } + } + } + + @Nested + class TestUploadAttachmentFile { private static final AttachmentFile ATTACHMENT_FILE = AttachmentFileTestFactory.create(); + private static final String FILE_CONTENT_STR = new String(FILE_CONTENT); @Mock private AttachmentFile enhancedAttachmentFile; @@ -201,20 +221,46 @@ class AttachmentFileServiceTest { private OzgCloudUploadFile ozgCloudUploadFile; @Mock private InputStream contentStream; + @Mock + private Base64.Decoder decoder; + + private MockedStatic<Base64> base64Mock; @BeforeEach void init() { when(ozgCloudFileService.uploadFile(any(), any())).thenReturn(OzgCloudFileId.from(FILE_ID)); when(attachmentFileMapper.toOzgCloudUploadFile(any())).thenReturn(ozgCloudUploadFile); - doReturn(enhancedAttachmentFile).when(service).enhanceAttachmentFile(any(), any()); - doReturn(contentStream).when(service).toDecodedInputStream(any()); + doReturn(enhancedAttachmentFile).when(service).addContentTypeIfMissing(any(), any()); + doReturn(contentStream).when(service).toInputStream(any()); + base64Mock = mockStatic(Base64.class); + base64Mock.when(Base64::getDecoder).thenReturn(decoder); + when(decoder.decode(anyString())).thenReturn(FILE_CONTENT); + } + + @AfterEach + void close() { + base64Mock.close(); + } + + @Test + void shouldCallGetDecoder() { + createAttachmentFile(); + + base64Mock.verify(Base64::getDecoder); } @Test - void shouldCallEnhanceAttachmentFile() { + void shouldCallDecode() { createAttachmentFile(); - verify(service).enhanceAttachmentFile(ATTACHMENT_FILE, FILE_CONTENT); + verify(decoder).decode(FILE_CONTENT_STR); + } + + @Test + void shouldCallAddContentTypeIfMissing() { + createAttachmentFile(); + + verify(service).addContentTypeIfMissing(ATTACHMENT_FILE, FILE_CONTENT); } @Test @@ -228,7 +274,7 @@ class AttachmentFileServiceTest { void shouldCallToDecodedInputStream() { createAttachmentFile(); - verify(service).toDecodedInputStream(FILE_CONTENT); + verify(service).toInputStream(FILE_CONTENT); } @Test @@ -246,12 +292,12 @@ class AttachmentFileServiceTest { } private String createAttachmentFile() { - return service.createAttachmentFile(ATTACHMENT_FILE, FILE_CONTENT); + return service.uploadAttachmentFile(ATTACHMENT_FILE, FILE_CONTENT_STR); } } @Nested - class TestEnhanceAttachmentFile { + class TestAddContentTypeIfMissing { private AttachmentFile attachmentFile; @@ -289,7 +335,7 @@ class AttachmentFileServiceTest { } private AttachmentFile enhanceAttachmentFile() { - return service.enhanceAttachmentFile(attachmentFile, FILE_CONTENT); + return service.addContentTypeIfMissing(attachmentFile, FILE_CONTENT); } } @@ -343,6 +389,7 @@ class AttachmentFileServiceTest { assertThat(result).isEqualTo(AttachmentFileTestFactory.CONTENT_TYPE); } + } @Nested @@ -426,125 +473,68 @@ class AttachmentFileServiceTest { @Nested class TestGetTypeByContent { - private static final AttachmentFile ATTACHMENT_FILE = AttachmentFileTestFactory.create(); - - @Mock - private InputStream contentStream; - private MockedStatic<URLConnection> urlConnectionMock; - - @BeforeEach - void init() { - urlConnectionMock = mockStatic(URLConnection.class); - doReturn(contentStream).when(service).toInputStream(any()); - } - - @AfterEach - void close() { - urlConnectionMock.close(); - } - - @Test - void shouldCallToInputStream() { - getTypeByContent(); - - verify(service).toInputStream(FILE_CONTENT); - } - - @Test - void shouldCallGuessContentTypeFromStream() { - getTypeByContent(); - - urlConnectionMock.verify(() -> URLConnection.guessContentTypeFromStream(contentStream)); - } - + @SneakyThrows @Test void shouldReturnContentType() { - urlConnectionMock.when(() -> URLConnection.guessContentTypeFromStream(any())).thenReturn(AttachmentFileTestFactory.CONTENT_TYPE); + var content = TestUtils.loadFile("BspQuittung.xml").readAllBytes(); - var result = getTypeByContent(); + var result = service.getTypeByContent(content); - assertThat(result).contains(AttachmentFileTestFactory.CONTENT_TYPE); + assertThat(result).contains("application/xml"); } @Test void shouldReturnEmpty() { - var result = getTypeByContent(); + var result = service.getTypeByContent(FILE_CONTENT); assertThat(result).isEmpty(); } @Test void shouldNotThrowException() { - urlConnectionMock.when(() -> URLConnection.guessContentTypeFromStream(any())).thenThrow(IOException.class); - - var result = getTypeByContent(); - - assertThat(result).isEmpty(); - } + try (var urlConnectionMock = mockStatic(URLConnection.class)) { + urlConnectionMock.when(() -> URLConnection.guessContentTypeFromStream(any())).thenThrow(IOException.class); - private Optional<String> getTypeByContent() { - return service.getTypeByContent(FILE_CONTENT); - } - } + var result = service.getTypeByContent(FILE_CONTENT); - @Nested - class TestGetByMimeTypes { + assertThat(result).isEmpty(); + } - @BeforeEach - void init() { } - @AfterEach - void close() { - } + @Nested + class TestGetByMimeTypes { - @Test - void shouldCallGetContentType() { - getByMimeTypes(); + @Test + void shouldCallGetContentType() { + getByMimeTypes(); - verify(mimetypesFileTypeMap).getContentType(AttachmentFileTestFactory.NAME); - } + verify(mimetypesFileTypeMap).getContentType(AttachmentFileTestFactory.NAME); + } - @Test - void shouldReturnContentType() { - when(mimetypesFileTypeMap.getContentType(anyString())).thenReturn(AttachmentFileTestFactory.CONTENT_TYPE); + @Test + void shouldReturnContentType() { + when(mimetypesFileTypeMap.getContentType(anyString())).thenReturn(AttachmentFileTestFactory.CONTENT_TYPE); - var result = getByMimeTypes(); + var result = getByMimeTypes(); - assertThat(result).isEqualTo(AttachmentFileTestFactory.CONTENT_TYPE); - } + assertThat(result).isEqualTo(AttachmentFileTestFactory.CONTENT_TYPE); + } - private String getByMimeTypes() { - return service.getByMimeTypes(AttachmentFileTestFactory.create()); + private String getByMimeTypes() { + return service.getByMimeTypes(AttachmentFileTestFactory.create()); + } } } @Nested - class TestToDecodedInputStream { - - @Mock - private Base64.Decoder decoder; - - private MockedStatic<Base64> base64Mock; - - @BeforeEach - void init() { - base64Mock = mockStatic(Base64.class); - base64Mock.when(Base64::getDecoder).thenReturn(decoder); - } - - @AfterEach - void close() { - base64Mock.close(); - } + class TestToInputStream { @Test void shouldReturnInputStream() { - when(decoder.decode(anyString())).thenReturn(FILE_CONTENT.getBytes()); - - var result = service.toDecodedInputStream(FILE_CONTENT); + var result = service.toInputStream(FILE_CONTENT); - assertThat(result).hasBinaryContent(FILE_CONTENT.getBytes()); + assertThat(result).hasBinaryContent(FILE_CONTENT); } } } \ No newline at end of file diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentServiceTest.java index 7160dc4e754c27a04ec77943a4a8b7b66165ad4e..3a16696cab0b269da392fc7fc372b6323d913890 100644 --- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentServiceTest.java +++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/osi/MessageAttachmentServiceTest.java @@ -198,7 +198,7 @@ class MessageAttachmentServiceTest { @BeforeEach void init() { doReturn(attachmentFile).when(service).buildAttachmentFile(any(), any()); - when(attachmentFileService.createAttachmentFile(any(), any())).thenReturn(ATTACHMENT_FILE_ID); + when(attachmentFileService.uploadAttachmentFile(any(), any())).thenReturn(ATTACHMENT_FILE_ID); } @Test @@ -212,7 +212,7 @@ class MessageAttachmentServiceTest { void shouldCallCreateAttachmentFile() { persistAttachment(); - verify(attachmentFileService).createAttachmentFile(attachmentFile, MessageAttachmentTestFactory.CONTENT); + verify(attachmentFileService).uploadAttachmentFile(attachmentFile, MessageAttachmentTestFactory.CONTENT); } @Test