From 32ce9431d305a71238b3d5ddf893595e3fdba731 Mon Sep 17 00:00:00 2001 From: Pavel Bezliapovich Date: Thu, 19 Dec 2024 14:51:40 +0100 Subject: [PATCH] feat: Added logic for handling unavailable images Refs: #307 --- .../util/PdfExporterFileResourceProvider.java | 18 +-- .../PdfExporterFileResourceProviderTest.java | 106 +++++++++++------- 2 files changed, 74 insertions(+), 50 deletions(-) diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProvider.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProvider.java index 0fd789d..6d3cf9d 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProvider.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProvider.java @@ -89,13 +89,12 @@ private byte[] getResourceAsBytesImpl(String resource, List unavailableW InputStream stream = resolver.resolve(resource); if (stream != null) { byte[] result = StreamUtils.suckStreamThenClose(stream); - if (result.length > 0) { - if (WorkItemAttachmentUrlResolver.isWorkItemAttachmentUrl(resource) && isMediaTypeMismatch(resource, result)) { - unavailableWorkItemAttachments.add(getWorkItemIdFromAttachmentUrl(resource)); - return getDefaultContent(resource); - } - return result; + if (result.length > 0 && WorkItemAttachmentUrlResolver.isWorkItemAttachmentUrl(resource) && isMediaTypeMismatch(resource, result)) { + unavailableWorkItemAttachments.add(getWorkItemIdFromAttachmentUrl(resource)); + return getDefaultContent(resource); } + return result; + } } } @@ -119,8 +118,8 @@ byte[] getDefaultContent(String resource) throws IOException { } else { return new byte[0]; } - File sorryBear = new File(BundleHelper.getPath("com.polarion.alm.ui", defaultImagePath)); - return StreamUtils.suckStreamThenClose(new FileInputStream(sorryBear)); + File defaultImage = new File(BundleHelper.getPath("com.polarion.alm.ui", defaultImagePath)); + return StreamUtils.suckStreamThenClose(new FileInputStream(defaultImage)); } @VisibleForTesting @@ -163,8 +162,9 @@ public byte[] processPossibleSvgImage(byte[] possibleSvgImageBytes) { /** * Remove GenericUrlResolver because it has no explicit timeouts declared */ + @VisibleForTesting @SneakyThrows - private IAttachmentUrlResolver getPolarionUrlResolverWithoutGenericUrlChildResolver() { + IAttachmentUrlResolver getPolarionUrlResolverWithoutGenericUrlChildResolver() { IAttachmentUrlResolver attachmentUrlResolver = PolarionUrlResolver.getInstance(); if (attachmentUrlResolver instanceof ParentUrlResolver parentUrlResolver) { diff --git a/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProviderTest.java b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProviderTest.java index 8093bec..8e2bacc 100644 --- a/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProviderTest.java +++ b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/util/PdfExporterFileResourceProviderTest.java @@ -2,19 +2,22 @@ import ch.sbb.polarion.extension.generic.test_extensions.PlatformContextMockExtension; import ch.sbb.polarion.extension.generic.test_extensions.TransactionalExecutorExtension; +import com.polarion.alm.tracker.internal.url.GenericUrlResolver; +import com.polarion.alm.tracker.internal.url.IAttachmentUrlResolver; import com.polarion.alm.tracker.internal.url.IUrlResolver; +import com.polarion.alm.tracker.internal.url.ParentUrlResolver; +import com.polarion.alm.tracker.internal.url.PolarionUrlResolver; import lombok.SneakyThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.MockedStatic; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; @@ -23,7 +26,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @ExtendWith({ MockitoExtension.class, @@ -32,7 +35,7 @@ }) class PdfExporterFileResourceProviderTest { @Mock - PdfExporterFileResourceProvider fileResourceProviderMock; + PdfExporterFileResourceProvider resourceProviderMock; @Mock private IUrlResolver resolverMock; @@ -48,7 +51,28 @@ void setUp() { } @Test - void getResourceAsBytesSuccess() throws IOException { + void processPossibleSvgImageTest() { + byte[] basicString = "basic".getBytes(StandardCharsets.UTF_8); + assertArrayEquals(basicString, resourceProvider.processPossibleSvgImage(basicString)); + } + + @Test + @SneakyThrows + void replaceImagesAsBase64EncodedTest() { + byte[] imgBytes; + try (InputStream is = this.getClass().getResourceAsStream("/test_img.png")) { + imgBytes = is != null ? is.readAllBytes() : new byte[0]; + } + + when(resourceProviderMock.getResourceAsBytes("http://localhost/some-path/img.png", null)).thenReturn(imgBytes); + when(resourceProviderMock.getResourceAsBase64String(any(), eq(null))).thenCallRealMethod(); + String result = resourceProviderMock.getResourceAsBase64String("http://localhost/some-path/img.png", null); + assertEquals("data:image/png;base64," + Base64.getEncoder().encodeToString(imgBytes), result); + } + + @Test + @SneakyThrows + void getResourceAsBytesSuccess() { when(resolverMock.canResolve(TEST_RESOURCE)).thenReturn(true); when(resolverMock.resolve(TEST_RESOURCE)).thenReturn(new ByteArrayInputStream(TEST_CONTENT)); @@ -60,7 +84,8 @@ void getResourceAsBytesSuccess() throws IOException { } @Test - void getResourceAsBytesNoResolverFound() throws IOException { + @SneakyThrows + void getResourceAsBytesNoResolverFound() { when(resolverMock.canResolve(TEST_RESOURCE)).thenReturn(false); List unavailableAttachments = new ArrayList<>(); @@ -71,7 +96,8 @@ void getResourceAsBytesNoResolverFound() throws IOException { } @Test - void getResourceAsBytesResolverReturnsNull() throws IOException { + @SneakyThrows + void getResourceAsBytesResolverReturnsNull() { when(resolverMock.canResolve(TEST_RESOURCE)).thenReturn(true); when(resolverMock.resolve(TEST_RESOURCE)).thenReturn(null); @@ -93,38 +119,18 @@ void getResourceAsBytesExceptionHandling() { assertTrue(unavailableAttachments.isEmpty()); } - @Test - void processPossibleSvgImageTest() { - byte[] basicString = "basic".getBytes(StandardCharsets.UTF_8); - assertArrayEquals(basicString, resourceProvider.processPossibleSvgImage(basicString)); - } - - @Test - @SneakyThrows - void replaceImagesAsBase64EncodedTest() { - byte[] imgBytes; - try (InputStream is = this.getClass().getResourceAsStream("/test_img.png")) { - imgBytes = is != null ? is.readAllBytes() : new byte[0]; - } - - when(fileResourceProviderMock.getResourceAsBytes("http://localhost/some-path/img.png", null)).thenReturn(imgBytes); - when(fileResourceProviderMock.getResourceAsBase64String(any(), eq(null))).thenCallRealMethod(); - String result = fileResourceProviderMock.getResourceAsBase64String("http://localhost/some-path/img.png", null); - assertEquals("data:image/png;base64," + Base64.getEncoder().encodeToString(imgBytes), result); - } - @Test void isMediaTypeMismatchMatchingMimeTypes() { String resource = "image.png"; byte[] content = new byte[0]; - try (MockedStatic mockedMediaUtils = Mockito.mockStatic(MediaUtils.class)) { + try (MockedStatic mockedMediaUtils = mockStatic(MediaUtils.class)) { mockedMediaUtils.when(() -> MediaUtils.getMimeTypeUsingTikaByContent(resource, content)) .thenReturn("image/png"); mockedMediaUtils.when(() -> MediaUtils.getMimeTypeUsingTikaByResourceName(resource, null)) .thenReturn("image/png"); - boolean result = fileResourceProviderMock.isMediaTypeMismatch(resource, content); + boolean result = resourceProviderMock.isMediaTypeMismatch(resource, content); assertFalse(result); } } @@ -133,26 +139,44 @@ void isMediaTypeMismatchMatchingMimeTypes() { @SneakyThrows void getDefaultContentEmptyForNonImage() { String resource = "attachment.txt"; - try (MockedStatic mockedMediaUtils = Mockito.mockStatic(MediaUtils.class)) { + try (MockedStatic mockedMediaUtils = mockStatic(MediaUtils.class)) { mockedMediaUtils.when(() -> MediaUtils.getImageFormat(resource)) .thenReturn(""); - byte[] content = fileResourceProviderMock.getDefaultContent(resource); + byte[] content = resourceProviderMock.getDefaultContent(resource); assertNull(content); } } @Test - void getWorkItemIdFromAttachmentUrlValidUrl() { - String url = "http://localhost/polarion/wi-attachment/elibrary/EL-14852/attachment.png"; - String result = resourceProvider.getWorkItemIdFromAttachmentUrl(url); - assertEquals("EL-14852", result); - } + @SuppressWarnings("unchecked") + void getPolarionUrlResolverWithoutGenericUrlChildResolver() throws Exception { + ParentUrlResolver parentUrlResolverMock = mock(ParentUrlResolver.class); + Field childResolversField = ParentUrlResolver.class.getDeclaredField("childResolvers"); + childResolversField.setAccessible(true); - @Test - void getWorkItemIdFromAttachmentUrl_InvalidUrl() { - String url = "http://example.com/invalid/url"; - String result = fileResourceProviderMock.getWorkItemIdFromAttachmentUrl(url); - assertNull(result); + IUrlResolver mockResolver1 = mock(IUrlResolver.class); + IUrlResolver mockResolver2 = mock(GenericUrlResolver.class); + IUrlResolver mockResolver3 = mock(IUrlResolver.class); + + List childResolvers = List.of(mockResolver1, mockResolver2, mockResolver3); + childResolversField.set(parentUrlResolverMock, childResolvers); + + try (MockedStatic polarionUrlResolverMock = mockStatic(PolarionUrlResolver.class)) { + polarionUrlResolverMock.when(PolarionUrlResolver::getInstance).thenReturn(parentUrlResolverMock); + + IAttachmentUrlResolver result = resourceProvider.getPolarionUrlResolverWithoutGenericUrlChildResolver(); + + assertTrue(result instanceof ParentUrlResolver); + ParentUrlResolver resultParent = (ParentUrlResolver) result; + + List filteredResolvers = + (List) childResolversField.get(resultParent); + + assertEquals(2, filteredResolvers.size()); + assertTrue(filteredResolvers.contains(mockResolver1)); + assertTrue(filteredResolvers.contains(mockResolver3)); + assertFalse(filteredResolvers.contains(mockResolver2)); + } } }