From 7491093a5a7326a1bdd4a4ee5eec3d6afe0716ae Mon Sep 17 00:00:00 2001 From: "AAVN\\pvquan" Date: Wed, 25 Dec 2024 12:01:26 +0700 Subject: [PATCH] MARP-1687 Write unit test --- .../market/constants/DirectoryConstants.java | 1 - .../market/constants/PreviewConstants.java | 13 ++ .../impl/ReleasePreviewServiceImpl.java | 15 +- .../impl/ReleasePreviewServiceImplTest.java | 195 ++++++++++++++++++ 4 files changed, 216 insertions(+), 8 deletions(-) create mode 100644 marketplace-service/src/main/java/com/axonivy/market/constants/PreviewConstants.java create mode 100644 marketplace-service/src/test/java/com/axonivy/market/service/impl/ReleasePreviewServiceImplTest.java diff --git a/marketplace-service/src/main/java/com/axonivy/market/constants/DirectoryConstants.java b/marketplace-service/src/main/java/com/axonivy/market/constants/DirectoryConstants.java index 697212cd0..df52f70e4 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/constants/DirectoryConstants.java +++ b/marketplace-service/src/main/java/com/axonivy/market/constants/DirectoryConstants.java @@ -8,5 +8,4 @@ public class DirectoryConstants { public static final String DATA_DIR = "data"; public static final String WORK_DIR = "work"; public static final String CACHE_DIR = "market-cache"; - public static final String PREVIEW_DIR = "marketplace-service/release-preview"; } diff --git a/marketplace-service/src/main/java/com/axonivy/market/constants/PreviewConstants.java b/marketplace-service/src/main/java/com/axonivy/market/constants/PreviewConstants.java new file mode 100644 index 000000000..d9fce76aa --- /dev/null +++ b/marketplace-service/src/main/java/com/axonivy/market/constants/PreviewConstants.java @@ -0,0 +1,13 @@ +package com.axonivy.market.constants; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class PreviewConstants { + + public static final String PREVIEW_DIR = "marketplace-service/release-preview"; + + public static final String IMAGE_DOWNLOAD_URL = "%s/api/image/preview/%s"; + +} diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/impl/ReleasePreviewServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/service/impl/ReleasePreviewServiceImpl.java index 48a1c0962..81795cc91 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/impl/ReleasePreviewServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/impl/ReleasePreviewServiceImpl.java @@ -26,14 +26,14 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import static com.axonivy.market.constants.DirectoryConstants.PREVIEW_DIR; +import static com.axonivy.market.constants.PreviewConstants.IMAGE_DOWNLOAD_URL; +import static com.axonivy.market.constants.PreviewConstants.PREVIEW_DIR; @Log4j2 @Service @AllArgsConstructor public class ReleasePreviewServiceImpl implements ReleasePreviewService { - private final static String IMAGE_DOWNLOAD_URL = "%s/api/image/preview/%s"; @Override public ReleasePreview extract(MultipartFile file, String baseUrl) { @@ -41,7 +41,7 @@ public ReleasePreview extract(MultipartFile file, String baseUrl) { return extractREADME(baseUrl); } - private void unzip(MultipartFile file) { + public void unzip(MultipartFile file) { try { File extractDir = new File(PREVIEW_DIR); prepareUnZipDirectory(extractDir.toPath()); @@ -70,7 +70,7 @@ private void unzip(MultipartFile file) { } } - private ReleasePreview extractREADME(String baseUrl) { + public ReleasePreview extractREADME(String baseUrl) { Map> moduleContents = new HashMap<>(); try (Stream readmePathStream = Files.walk(Paths.get(PREVIEW_DIR))) { List readmeFiles = readmePathStream.filter(Files::isRegularFile) @@ -85,7 +85,7 @@ private ReleasePreview extractREADME(String baseUrl) { return ReleasePreview.from(moduleContents); } catch (IOException e) { log.error("Cannot get README file's content from folder {}: {}", - com.axonivy.market.constants.DirectoryConstants.PREVIEW_DIR, e.getMessage()); + PREVIEW_DIR, e.getMessage()); return null; } } @@ -111,7 +111,7 @@ public String updateImagesWithDownloadUrl(String unzippedFolderPath, } } - private static void prepareUnZipDirectory(Path directory) { + public void prepareUnZipDirectory(Path directory) { try { if (Files.exists(directory)) { Files.walk(directory) @@ -125,7 +125,7 @@ private static void prepareUnZipDirectory(Path directory) { } } - private void processReadme(Path readmeFile, Map> moduleContents, + public void processReadme(Path readmeFile, Map> moduleContents, String baseUrl) throws IOException { String readmeContents = Files.readString(readmeFile); if (ProductContentUtils.hasImageDirectives(readmeContents)) { @@ -138,4 +138,5 @@ private void processReadme(Path readmeFile, Map> mod readmeContentsModel ); } + } diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/impl/ReleasePreviewServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/impl/ReleasePreviewServiceImplTest.java new file mode 100644 index 000000000..a274fe0d3 --- /dev/null +++ b/marketplace-service/src/test/java/com/axonivy/market/service/impl/ReleasePreviewServiceImplTest.java @@ -0,0 +1,195 @@ +package com.axonivy.market.service.impl; + +import com.axonivy.market.model.ReleasePreview; +import com.axonivy.market.util.FileUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockMultipartFile; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static com.axonivy.market.constants.PreviewConstants.IMAGE_DOWNLOAD_URL; +import static com.axonivy.market.constants.PreviewConstants.PREVIEW_DIR; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +; + +@ExtendWith(MockitoExtension.class) +class ReleasePreviewServiceImplTest { + + private ReleasePreviewServiceImpl releasePreviewService; + private Path tempDirectory; + + private final String baseUrl = "http://example.com"; + + private final String readmeContent = "# Sample README Content\n![image](image1.png)"; + + private final String updatedReadme = "# Sample README Content\n![image](http://example" + + ".com/api/image/preview/image1.png)"; + + @BeforeEach + void setUp() throws IOException { + releasePreviewService = spy(new ReleasePreviewServiceImpl()); + tempDirectory = Files.createTempDirectory("test-dir"); + } + + @AfterEach + void tearDown() throws IOException { + clear(tempDirectory); + clear(Path.of(PREVIEW_DIR).getParent()); + } + + private void clear(Path path) throws IOException { + if (Files.exists(path)) { + Files.walk(path) + .sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(java.io.File::delete); + } + } + + @Test + void testProcessReadme() throws IOException { + Path tempReadmeFile = Files.createTempFile("README", ".md"); + Files.writeString(tempReadmeFile, readmeContent); + Map> moduleContents = new HashMap<>(); + doReturn(updatedReadme).when(releasePreviewService) + .updateImagesWithDownloadUrl(PREVIEW_DIR, readmeContent, baseUrl); + releasePreviewService.processReadme(tempReadmeFile, moduleContents, baseUrl); + assertEquals(3, moduleContents.size()); + Files.deleteIfExists(tempReadmeFile); + } + + @Test + void testPrepareUnZipDirectory() { + releasePreviewService.prepareUnZipDirectory(tempDirectory); + assertTrue(Files.exists(tempDirectory)); + } + + @Test + void testPrepareUnZipDirectory_IOException() { + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + mockedFiles.when(() -> Files.exists(tempDirectory)).thenReturn(true); + } + assertDoesNotThrow(() -> releasePreviewService.prepareUnZipDirectory(tempDirectory)); + } + + @Test + void testUpdateImagesWithDownloadUrl_Success() throws IOException { + Path tempReadmeFile = Files.createTempFile("README", ".md"); + Files.writeString(tempReadmeFile, readmeContent); + String parentPath = tempReadmeFile.getParent().toString(); + + Path imagePath1 = Paths.get(parentPath + "/image1.png"); + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + mockedFiles.when(() -> Files.walk(Paths.get(parentPath))) + .thenReturn(Stream.of(imagePath1)); + mockedFiles.when(() -> Files.isRegularFile(any())) + .thenReturn(true); + String result = releasePreviewService.updateImagesWithDownloadUrl(parentPath, + readmeContent + , baseUrl); + + assertNotNull(result); + assertTrue(result.contains(String.format(IMAGE_DOWNLOAD_URL, baseUrl, "image1.png"))); + } + } + + @Test + void testUpdateImagesWithDownloadUrl_IOException() { + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + mockedFiles.when(() -> Files.walk(tempDirectory)) + .thenThrow(new IOException("Simulated IOException")); + String result = releasePreviewService.updateImagesWithDownloadUrl(tempDirectory.toString(), readmeContent, + baseUrl); + assertNull(result); + assertDoesNotThrow( + () -> releasePreviewService.updateImagesWithDownloadUrl(tempDirectory.toString(), readmeContent, baseUrl)); + } + } + + @Test + void testExtractREADME_Success() throws IOException { + String parentPath = tempDirectory.getParent().toString(); + Path readmeFile1 = FileUtils.createFile(parentPath + "/README.md").toPath(); + Files.writeString(readmeFile1, readmeContent); + + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + mockedFiles.when(() -> Files.walk(Paths.get(PREVIEW_DIR))) + .thenReturn(Stream.of(readmeFile1)); + mockedFiles.when(() -> Files.isRegularFile(any())) + .thenReturn(true); + mockedFiles.when(() -> Files.readString(any())) + .thenReturn(readmeContent); + when(releasePreviewService.updateImagesWithDownloadUrl(any(), anyString(), anyString())).thenReturn( + updatedReadme); + ReleasePreview result = releasePreviewService.extractREADME(baseUrl); + assertNotNull(result); + } + } + + @Test + void testExtractREADME_NoReadmeFiles() { + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + mockedFiles.when(() -> Files.walk(Paths.get(PREVIEW_DIR))) + .thenReturn(Stream.empty()); + ReleasePreview result = releasePreviewService.extractREADME(baseUrl); + assertNull(result); + mockedFiles.verify(() -> Files.walk(Paths.get(PREVIEW_DIR)), times(1)); + } + } + + @Test + void testExtractREADME_IOException() { + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + mockedFiles.when(() -> Files.walk(Paths.get(PREVIEW_DIR))) + .thenThrow(new IOException("Simulated IOException")); + ReleasePreview result = releasePreviewService.extractREADME(baseUrl); + assertNull(result); + assertDoesNotThrow( + () -> releasePreviewService.extractREADME(baseUrl)); + } + } + + @Test + void testUnzip_Success() throws Exception { + String mockFileName = "test.zip"; + byte[] zipContent = createMockZipContent(); + MockMultipartFile mockMultipartFile = new MockMultipartFile("file", mockFileName, "application/zip", zipContent); + Path path = Paths.get(PREVIEW_DIR); + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + mockedFiles.when(() -> Files.exists(path)).thenReturn(false); + mockedFiles.when(() -> Files.createDirectories(path)).thenReturn(null); + releasePreviewService.unzip(mockMultipartFile); + mockedFiles.verify(() -> Files.exists(path), times(1)); + mockedFiles.verify(() -> Files.createDirectories(path), times(1)); + } + } + + private byte[] createMockZipContent() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ZipOutputStream zos = new ZipOutputStream(baos)) { + ZipEntry entry = new ZipEntry("mockFile.txt"); + zos.putNextEntry(entry); + zos.write("Mock file content".getBytes()); + zos.closeEntry(); + } + return baos.toByteArray(); + } + +}