diff --git a/core/src/main/java/org/mapfish/print/map/geotools/FeaturesParser.java b/core/src/main/java/org/mapfish/print/map/geotools/FeaturesParser.java index 9d84a43b91..13b8df38a9 100644 --- a/core/src/main/java/org/mapfish/print/map/geotools/FeaturesParser.java +++ b/core/src/main/java/org/mapfish/print/map/geotools/FeaturesParser.java @@ -61,7 +61,7 @@ public FeaturesParser( } @VisibleForTesting - static final CoordinateReferenceSystem parseCoordinateReferenceSystem( + static CoordinateReferenceSystem parseCoordinateReferenceSystem( final MfClientHttpRequestFactory requestFactory, final JSONObject geojson, final boolean forceLongitudeFirst) { @@ -108,7 +108,8 @@ static final CoordinateReferenceSystem parseCoordinateReferenceSystem( } } } else { - LOGGER.warn("Unable to load linked CRS from geojson: \n{}", crsJson); + LOGGER.warn( + "Unsupported link type {} in linked CRS from geojson: \n{}", linkType, crsJson); } } else { code.append(getProperty(crsJson, "code")); @@ -147,7 +148,6 @@ private static String getProperty(final JSONObject crsJson, final String nameCod * @param template the template * @param features what to parse * @return the feature collection - * @throws IOException */ public final SimpleFeatureCollection autoTreat(final Template template, final String features) throws IOException { @@ -189,7 +189,6 @@ public final SimpleFeatureCollection treatStringAsURL( * * @param geoJsonString what to parse * @return the feature collection - * @throws IOException */ public final SimpleFeatureCollection treatStringAsGeoJson(final String geoJsonString) throws IOException { @@ -231,7 +230,7 @@ private SimpleFeatureType createFeatureType(@Nonnull final String geojsonData) { builder.setName("GeosjonFeatureType"); final JSONArray features = geojson.getJSONArray("features"); - if (features.length() == 0) { + if (features.isEmpty()) { // do not try to build the feature type if there are no features return null; } diff --git a/core/src/main/java/org/mapfish/print/map/style/ParserPluginUtils.java b/core/src/main/java/org/mapfish/print/map/style/ParserPluginUtils.java index d965fabb8d..4fc4635c5e 100644 --- a/core/src/main/java/org/mapfish/print/map/style/ParserPluginUtils.java +++ b/core/src/main/java/org/mapfish/print/map/style/ParserPluginUtils.java @@ -34,7 +34,7 @@ public static Optional<Style> loadStyleAsURI( final ClientHttpRequestFactory clientHttpRequestFactory, final String styleRef, final Function<byte[], @Nullable Optional<Style>> loadFunction) { - int statusCode; + int httpStatusCode; final byte[] input; URI uri; @@ -47,13 +47,13 @@ public static Optional<Style> loadStyleAsURI( try { final ClientHttpRequest request = clientHttpRequestFactory.createRequest(uri, HttpMethod.GET); try (ClientHttpResponse response = request.execute()) { - statusCode = response.getRawStatusCode(); + httpStatusCode = response.getRawStatusCode(); input = IOUtils.toByteArray(response.getBody()); } } catch (Exception e) { return Optional.empty(); } - if (statusCode == HttpStatus.OK.value()) { + if (httpStatusCode == HttpStatus.OK.value()) { return loadFunction.apply(input); } else { return Optional.empty(); diff --git a/core/src/main/java/org/mapfish/print/processor/jasper/HttpImageResolver.java b/core/src/main/java/org/mapfish/print/processor/jasper/HttpImageResolver.java index f8a5987e48..5bc6ee6fd5 100644 --- a/core/src/main/java/org/mapfish/print/processor/jasper/HttpImageResolver.java +++ b/core/src/main/java/org/mapfish/print/processor/jasper/HttpImageResolver.java @@ -1,5 +1,6 @@ package org.mapfish.print.processor.jasper; +import com.google.common.annotations.VisibleForTesting; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URI; @@ -29,7 +30,7 @@ public final class HttpImageResolver implements TableColumnConverter<BufferedIma private static final int IMAGE_SIZE = 48; private Pattern urlExtractor = Pattern.compile("(.*)"); private int urlGroup = 1; - private final BufferedImage defaultImage; + @VisibleForTesting final BufferedImage defaultImage; /** Constructor. */ public HttpImageResolver() { diff --git a/core/src/main/java/org/mapfish/print/processor/jasper/LegendProcessor.java b/core/src/main/java/org/mapfish/print/processor/jasper/LegendProcessor.java index f6c17d4629..8ff512b78a 100644 --- a/core/src/main/java/org/mapfish/print/processor/jasper/LegendProcessor.java +++ b/core/src/main/java/org/mapfish/print/processor/jasper/LegendProcessor.java @@ -2,6 +2,7 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; +import com.google.common.annotations.VisibleForTesting; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; @@ -161,7 +162,14 @@ private void createTasks( if (icons != null && icons.length > 0) { for (URL icon : icons) { tasks.add( - new IconTask(icon, dpi, context, level, tempTaskDirectory, clientHttpRequestFactory)); + new IconTask( + icon, + dpi, + context, + level, + tempTaskDirectory, + clientHttpRequestFactory, + metricRegistry)); } } if (legendAttributes.classes != null) { @@ -269,7 +277,8 @@ protected void extraValidation( // no checks needed } - private synchronized BufferedImage getMissingImage() { + @VisibleForTesting + synchronized BufferedImage getMissingImage() { if (this.missingImage == null) { this.missingImage = new BufferedImage( @@ -311,7 +320,7 @@ public static final class Output { /** The datasource for the legend object in the report. */ public final JRTableModelDataSource legendDataSource; - /** The path to the compiled subreport. */ + /** The path to the compiled sub-report. */ public final String legendSubReport; /** The number of rows in the legend. */ @@ -343,7 +352,8 @@ public Object[] call() { } } - private final class IconTask implements Callable<Object[]> { + @VisibleForTesting + final class IconTask implements Callable<Object[]> { private final URL icon; private final double iconDPI; @@ -351,20 +361,24 @@ private final class IconTask implements Callable<Object[]> { private final MfClientHttpRequestFactory clientHttpRequestFactory; private final int level; private final File tempTaskDirectory; + private final MetricRegistry metricRegistry; - private IconTask( + @VisibleForTesting + IconTask( final URL icon, final double iconDPI, final ExecutionContext context, final int level, final File tempTaskDirectory, - final MfClientHttpRequestFactory clientHttpRequestFactory) { + final MfClientHttpRequestFactory clientHttpRequestFactory, + final MetricRegistry metricRegistry) { this.icon = icon; this.iconDPI = iconDPI; this.context = context; this.level = level; this.clientHttpRequestFactory = clientHttpRequestFactory; this.tempTaskDirectory = tempTaskDirectory; + this.metricRegistry = metricRegistry; } @Override @@ -389,8 +403,7 @@ private BufferedImage loadImage(final URI uri) { this.context.stopIfCanceled(); final ClientHttpRequest request = this.clientHttpRequestFactory.createRequest(uri, HttpMethod.GET); - try (Timer.Context ignored = - LegendProcessor.this.metricRegistry.timer(metricName).time()) { + try (Timer.Context ignored = metricRegistry.timer(metricName).time()) { try (ClientHttpResponse httpResponse = request.execute()) { if (httpResponse.getRawStatusCode() == HttpStatus.OK.value()) { image = ImageIO.read(httpResponse.getBody()); @@ -409,7 +422,7 @@ private BufferedImage loadImage(final URI uri) { if (image == null) { image = getMissingImage(); - LegendProcessor.this.metricRegistry.counter(metricName + ".error").inc(); + metricRegistry.counter(metricName + ".error").inc(); } return image; diff --git a/core/src/test/java/org/mapfish/print/map/geotools/FeaturesParserTest.java b/core/src/test/java/org/mapfish/print/map/geotools/FeaturesParserTest.java index 1b7f505464..5ef8a8f7d8 100644 --- a/core/src/test/java/org/mapfish/print/map/geotools/FeaturesParserTest.java +++ b/core/src/test/java/org/mapfish/print/map/geotools/FeaturesParserTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; @@ -36,6 +37,10 @@ public class FeaturesParserTest extends AbstractMapfishSpringTest { private static final String EXAMPLE_GEOJSONFILE = "geojson/geojson-inconsistent-attributes-2.json"; + private static final String WKT = + "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\"" + + ",SPHEROID[\"WGS_1984\",6378137,298.257223563]]" + + ",PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]]"; @Autowired private TestHttpClientFactory requestFactory; @Autowired private ConfigurationFactory configurationFactory; @@ -131,19 +136,32 @@ public MockClientHttpRequest handleRequest(URI uri, HttpMethod httpMethod) { @Test @DirtiesContext public void testParseCRSLinkEsriWkt() { + final MockClientHttpResponse clientHttpResponse = + new MockClientHttpResponse(WKT.getBytes(Constants.DEFAULT_CHARSET), HttpStatus.OK); + + CoordinateReferenceSystem crs = parseCoordinateReferenceSystemFromResponse(clientHttpResponse); + assertNotSame(DefaultEngineeringCRS.GENERIC_2D, crs); + } + + @Test + @DirtiesContext + public void testParseCRSLinkEsriWktWithUnsupportedErrorCode() { + final MockClientHttpResponse clientHttpResponse = + new MockClientHttpResponse(WKT.getBytes(Constants.DEFAULT_CHARSET), 999); + + CoordinateReferenceSystem crs = parseCoordinateReferenceSystemFromResponse(clientHttpResponse); + assertSame(DefaultEngineeringCRS.GENERIC_2D, crs); + } + + private CoordinateReferenceSystem parseCoordinateReferenceSystemFromResponse( + final MockClientHttpResponse clientHttpResponse) { requestFactory.registerHandler( input -> input != null && input.getHost().equals("spatialreference.org"), new TestHttpClientFactory.Handler() { @Override public MockClientHttpRequest handleRequest(URI uri, HttpMethod httpMethod) { - String wkt = - "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137,298" - + ".257223563]]," - + "PRIMEM[\"Greenwich\"," - + "0],UNIT[\"Degree\",0.017453292519943295]]"; MockClientHttpRequest mockClientHttpRequest = new MockClientHttpRequest(); - mockClientHttpRequest.setResponse( - new MockClientHttpResponse(wkt.getBytes(Constants.DEFAULT_CHARSET), HttpStatus.OK)); + mockClientHttpRequest.setResponse(clientHttpResponse); return mockClientHttpRequest; } }); @@ -161,10 +179,11 @@ public MockClientHttpRequest handleRequest(URI uri, HttpMethod httpMethod) { CoordinateReferenceSystem crs = FeaturesParser.parseCoordinateReferenceSystem(this.requestFactory, crsJSON, false); assertNotNull(crs); - assertNotSame(DefaultEngineeringCRS.GENERIC_2D, crs); + return crs; } - public void testParseCRSLinkProj4() { + @Test + public void testUnsupportedLinkTypeProj4() { JSONObject crsJSON = new JSONObject( "{\"crs\":{\n" @@ -179,7 +198,7 @@ public void testParseCRSLinkProj4() { CoordinateReferenceSystem crs = FeaturesParser.parseCoordinateReferenceSystem(this.requestFactory, crsJSON, false); assertNotNull(crs); - assertNotSame(DefaultEngineeringCRS.GENERIC_2D, crs); + assertSame(DefaultEngineeringCRS.GENERIC_2D, crs); } @Test diff --git a/core/src/test/java/org/mapfish/print/map/image/AbstractSingleImageLayerTest.java b/core/src/test/java/org/mapfish/print/map/image/AbstractSingleImageLayerTest.java new file mode 100644 index 0000000000..0be68f680d --- /dev/null +++ b/core/src/test/java/org/mapfish/print/map/image/AbstractSingleImageLayerTest.java @@ -0,0 +1,56 @@ +package org.mapfish.print.map.image; + +import static org.junit.Assert.assertTrue; + +import com.codahale.metrics.MetricRegistry; +import java.awt.image.BufferedImage; +import java.io.IOException; +import org.junit.Assert; +import org.junit.Test; +import org.mapfish.print.Constants; +import org.mapfish.print.attribute.map.MapfishMapContext; +import org.mapfish.print.http.MfClientHttpRequestFactory; +import org.mapfish.print.map.AbstractLayerParams; +import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.mock.http.client.MockClientHttpResponse; + +public class AbstractSingleImageLayerTest { + + @Test + public void testFetchImage() throws IOException { + MapfishMapContext mapContext = new MapfishMapContext(null, null, 100, 100, false, true); + MockClientHttpRequest mockClientHttpRequest = new MockClientHttpRequest(); + final int unsupportedStatusCode = 999; + mockClientHttpRequest.setResponse( + new MockClientHttpResponse( + "SomeResponse".getBytes(Constants.DEFAULT_CHARSET), unsupportedStatusCode)); + AbstractLayerParams layerParams = new AbstractLayerParams(); + layerParams.failOnError = true; + AbstractSingleImageLayer layer = new AbstractSingleImageLayerTestImpl(layerParams); + + try { + layer.fetchImage(mockClientHttpRequest, mapContext); + Assert.fail("Did not throw exception with unsupported status code"); + } catch (RuntimeException e) { + assertTrue(e.getMessage().contains(String.valueOf(unsupportedStatusCode))); + } + } + + private static class AbstractSingleImageLayerTestImpl extends AbstractSingleImageLayer { + + public AbstractSingleImageLayerTestImpl(AbstractLayerParams layerParams) { + super(null, null, layerParams, new MetricRegistry(), null); + } + + @Override + protected BufferedImage loadImage( + MfClientHttpRequestFactory requestFactory, MapfishMapContext transformer) { + return null; + } + + @Override + public RenderType getRenderType() { + return null; + } + } +} diff --git a/core/src/test/java/org/mapfish/print/map/style/ParserPluginUtilsTest.java b/core/src/test/java/org/mapfish/print/map/style/ParserPluginUtilsTest.java new file mode 100644 index 0000000000..2dfe7cd645 --- /dev/null +++ b/core/src/test/java/org/mapfish/print/map/style/ParserPluginUtilsTest.java @@ -0,0 +1,75 @@ +package org.mapfish.print.map.style; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.util.Optional; +import java.util.function.Function; +import org.geotools.api.style.Style; +import org.junit.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpResponse; + +public class ParserPluginUtilsTest { + + @Test + public void loadStyleAsURITest_ValidURI() throws IOException, URISyntaxException { + int httpStatusCode = HttpStatus.OK.value(); + Style style = mock(Style.class); + Optional<Style> actualStyle = testLoadingStyleWithStatusCode(style, httpStatusCode); + + assertTrue(actualStyle.isPresent()); + assertEquals(style, actualStyle.get()); + } + + private static Optional<Style> testLoadingStyleWithStatusCode( + final Style style, final int httpStatusCode) throws IOException, URISyntaxException { + ClientHttpRequestFactory factory = mock(ClientHttpRequestFactory.class); + ClientHttpRequest request = mock(ClientHttpRequest.class); + ClientHttpResponse response = mock(ClientHttpResponse.class); + + Function<byte[], Optional<Style>> function = bytes -> Optional.of(style); + + when(factory.createRequest(new URI("http://valid.uri"), HttpMethod.GET)).thenReturn(request); + when(request.execute()).thenReturn(response); + when(response.getRawStatusCode()).thenReturn(httpStatusCode); + when(response.getBody()) + .thenReturn( + new ByteArrayInputStream( + "This is dummy style data".getBytes(Charset.defaultCharset()))); + + return ParserPluginUtils.loadStyleAsURI(factory, "http://valid.uri", function); + } + + @Test + public void loadStyleAsURITest_InvalidStatusCode() throws IOException, URISyntaxException { + int httpStatusCode = 999; + Style style = mock(Style.class); + Optional<Style> actualStyle = testLoadingStyleWithStatusCode(style, httpStatusCode); + + assertFalse(actualStyle.isPresent()); + } + + @Test + public void loadStyleAsURITest_InValidURI() { + ClientHttpRequestFactory factory = mock(ClientHttpRequestFactory.class); + Style style = mock(Style.class); + + Function<byte[], Optional<Style>> function = bytes -> Optional.of(style); + + Optional<Style> actualStyle = + ParserPluginUtils.loadStyleAsURI(factory, "invalid|uri", function); + assertTrue(actualStyle.isEmpty()); + } +} diff --git a/core/src/test/java/org/mapfish/print/map/tiled/SingleTileLoaderTaskTest.java b/core/src/test/java/org/mapfish/print/map/tiled/SingleTileLoaderTaskTest.java new file mode 100644 index 0000000000..41f1539c0d --- /dev/null +++ b/core/src/test/java/org/mapfish/print/map/tiled/SingleTileLoaderTaskTest.java @@ -0,0 +1,78 @@ +package org.mapfish.print.map.tiled; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.codahale.metrics.MetricRegistry; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import org.junit.Test; +import org.mapfish.print.PrintException; +import org.mapfish.print.processor.AbstractProcessor; +import org.mapfish.print.processor.Processor; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.http.client.ClientHttpResponse; + +public class SingleTileLoaderTaskTest { + + @Test + public void testCompute() throws IOException, URISyntaxException { + final int unsupportedStatusCode = 200; + ClientHttpRequest tileRequest = mock(ClientHttpRequest.class); + CoverageTask.SingleTileLoaderTask task = prepareTest(unsupportedStatusCode, tileRequest); + + CoverageTask.Tile singleTile = task.compute(); + assertNotNull(singleTile); + verify(tileRequest, times(3)).getURI(); + } + + private CoverageTask.SingleTileLoaderTask prepareTest( + int unsupportedStatusCode, ClientHttpRequest tileRequest) + throws IOException, URISyntaxException { + BufferedImage errorImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + Processor.ExecutionContext context = new AbstractProcessor.Context(new HashMap<>()); + MetricRegistry registry = new MetricRegistry(); + + // mocking ClientHttpRequest + ClientHttpResponse clientHttpResponse = getMockResponse(unsupportedStatusCode); + when(tileRequest.execute()).thenReturn(clientHttpResponse); + when(tileRequest.getURI()).thenReturn(new URI("http://localhost")); + + return new CoverageTask.SingleTileLoaderTask( + tileRequest, errorImage, 0, 0, true, registry, context); + } + + @Test + public void testComputeWithUnsupportedStatusCode() throws IOException, URISyntaxException { + final int unsupportedStatusCode = 999; + ClientHttpRequest tileRequest = mock(ClientHttpRequest.class); + CoverageTask.SingleTileLoaderTask task = prepareTest(unsupportedStatusCode, tileRequest); + + try { + task.compute(); + fail("Did not throw exception with unsupported status code"); + } catch (PrintException e) { + assertTrue(e.getCause().getMessage().contains(String.valueOf(unsupportedStatusCode))); + verify(tileRequest, times(4)).getURI(); + } + } + + private ClientHttpResponse getMockResponse(int rawStatusCode) throws IOException { + ClientHttpResponse response = mock(ClientHttpResponse.class); + when(response.getRawStatusCode()).thenReturn(rawStatusCode); + when(response.getStatusCode()) + .thenThrow(new RuntimeException("Unsupported status code has no HttpStatus")); + when(response.getBody()).thenReturn(new ByteArrayInputStream(new byte[0])); + when(response.getHeaders()).thenReturn(new org.springframework.http.HttpHeaders()); + return response; + } +} diff --git a/core/src/test/java/org/mapfish/print/processor/jasper/HttpImageResolverTest.java b/core/src/test/java/org/mapfish/print/processor/jasper/HttpImageResolverTest.java new file mode 100644 index 0000000000..a8a5eda73d --- /dev/null +++ b/core/src/test/java/org/mapfish/print/processor/jasper/HttpImageResolverTest.java @@ -0,0 +1,128 @@ +package org.mapfish.print.processor.jasper; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.file.Files; +import org.junit.Test; +import org.mapfish.print.AbstractMapfishSpringTest; +import org.mapfish.print.http.MfClientHttpRequestFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.mock.http.client.MockClientHttpResponse; + +public class HttpImageResolverTest { + @Test + public void testResolve() throws IOException { + int statusCode = HttpStatus.OK.value(); + HttpImageResolver httpImageResolver = new HttpImageResolver(); + + BufferedImage result = resolveImageWithStatusCode(statusCode, httpImageResolver); + + // Assert that image is not the default one + assertNotEquals(httpImageResolver.defaultImage, result); + } + + private BufferedImage resolveImageWithStatusCode( + int statusCode, HttpImageResolver httpImageResolver) throws IOException { + String testUriString = "https://test.com/image.png"; + // Mock request factory and request + MfClientHttpRequestFactory requestFactoryMock = mock(MfClientHttpRequestFactory.class); + MockClientHttpRequest requestMock = new MockClientHttpRequest(); + when(requestFactoryMock.createRequest(any(URI.class), any())).thenReturn(requestMock); + + MockClientHttpResponse responseMock = buildMockResponse(statusCode); + try { + when(requestFactoryMock.createRequest( + new URI(testUriString), org.springframework.http.HttpMethod.GET)) + .thenReturn(requestMock); + requestMock.setResponse(responseMock); + } catch (Exception e) { + fail("Exception thrown: " + e.getMessage()); + } + + httpImageResolver.setUrlExtractor("(.*)"); + httpImageResolver.setUrlGroup(1); + + return httpImageResolver.resolve(requestFactoryMock, testUriString); + } + + @Test + public void testResolveWithUnsupportedStatus() throws IOException { + int statusCode = 999; + HttpImageResolver httpImageResolver = new HttpImageResolver(); + + BufferedImage result = resolveImageWithStatusCode(statusCode, httpImageResolver); + + // Assert that image is the default one + assertEquals(httpImageResolver.defaultImage, result); + } + + private MockClientHttpResponse buildMockResponse(int statusCode) throws IOException { + File file = AbstractMapfishSpringTest.getFile(this.getClass(), "/map-data/tiger-ny.png"); + byte[] responseBody = Files.readAllBytes(file.toPath()); + ByteArrayInputStream inputStream = new ByteArrayInputStream(responseBody); + MockClientHttpResponse responseMock = new MockClientHttpResponse(inputStream, statusCode); + responseMock.getHeaders().setContentType(MediaType.IMAGE_PNG); + return responseMock; + } + + @Test + public void testInvalidURIResolve() { + String invalidUriString = "htp:/invalid"; + MfClientHttpRequestFactory requestFactoryMock = mock(MfClientHttpRequestFactory.class); + HttpImageResolver httpImageResolver = new HttpImageResolver(); + httpImageResolver.setUrlExtractor("(.*)"); + httpImageResolver.setUrlGroup(1); + + // Calls the actual method with an invalid image + BufferedImage result = httpImageResolver.resolve(requestFactoryMock, invalidUriString); + + assertEquals(httpImageResolver.defaultImage, result); + } + + @Test + public void testInvalidUrlGroupResolve() throws IOException { + String testUriString = "https://test.com/image.png"; + MfClientHttpRequestFactory requestFactoryMock = mock(MfClientHttpRequestFactory.class); + MockClientHttpRequest requestMock = new MockClientHttpRequest(); + when(requestFactoryMock.createRequest(any(URI.class), any())).thenReturn(requestMock); + + byte[] responseBody = "Image bytes".getBytes(Charset.defaultCharset()); + MockClientHttpResponse responseMock = new MockClientHttpResponse(responseBody, HttpStatus.OK); + responseMock.getHeaders().setContentType(MediaType.IMAGE_PNG); + try { + when(requestFactoryMock.createRequest( + new URI(testUriString), org.springframework.http.HttpMethod.GET)) + .thenReturn(requestMock); + requestMock.setResponse(responseMock); + } catch (Exception e) { + fail("Exception thrown: " + e.getMessage()); + } + + HttpImageResolver httpImageResolver = new HttpImageResolver(); + httpImageResolver.setUrlExtractor("(.*)"); + int urlGroup = 2; + httpImageResolver.setUrlGroup(urlGroup); // Invalid group + + try { + // Calls the actual method with an invalid group + httpImageResolver.resolve(requestFactoryMock, testUriString); + fail("Did not throw IndexOutOfBoundsException for unsupported group"); + } catch (IndexOutOfBoundsException e) { + assertTrue(e.getMessage().contains("No group " + urlGroup)); + } + } +} diff --git a/core/src/test/java/org/mapfish/print/processor/jasper/IconTaskTest.java b/core/src/test/java/org/mapfish/print/processor/jasper/IconTaskTest.java new file mode 100644 index 0000000000..00f58b9a15 --- /dev/null +++ b/core/src/test/java/org/mapfish/print/processor/jasper/IconTaskTest.java @@ -0,0 +1,76 @@ +package org.mapfish.print.processor.jasper; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import com.codahale.metrics.MetricRegistry; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.HashMap; +import org.junit.Test; +import org.mapfish.print.http.MfClientHttpRequestFactory; +import org.mapfish.print.processor.AbstractProcessor; +import org.mapfish.print.processor.Processor; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.mock.http.client.MockClientHttpResponse; + +public class IconTaskTest { + + @Test + public void call_iconImageDoesNotExist_returnsMissingImageWhenOk() throws Exception { + int statusCode = HttpStatus.OK.value(); + BufferedImage missingImage = new BufferedImage(24, 24, BufferedImage.TYPE_INT_RGB); + + LegendProcessor.IconTask iconTask = prepareTest(missingImage, statusCode); + + Object[] result = iconTask.call(); + + assertEquals(missingImage, result[1]); + } + + @Test + public void call_iconImageDoesNotExist_returnsMissingImageWithUnsupportedStatus() + throws Exception { + int statusCode = 999; + BufferedImage missingImage = new BufferedImage(24, 24, BufferedImage.TYPE_INT_RGB); + + LegendProcessor.IconTask iconTask = prepareTest(missingImage, statusCode); + + Object[] result = iconTask.call(); + + assertEquals(missingImage, result[1]); + } + + private static LegendProcessor.IconTask prepareTest(BufferedImage missingImage, int statusCode) + throws URISyntaxException, IOException { + LegendProcessor legendProcessorMock = spy(LegendProcessor.class); + when(legendProcessorMock.getMissingImage()).thenReturn(missingImage); + Processor.ExecutionContext context = new AbstractProcessor.Context(new HashMap<>()); + URL icon = mock(URL.class); + when(icon.toURI()).thenReturn(new URI("http://localhost/icon.png")); + when(icon.getProtocol()).thenReturn("http"); + MfClientHttpRequestFactory requestFactoryMock = mock(MfClientHttpRequestFactory.class); + MockClientHttpRequest requestMock = new MockClientHttpRequest(); + when(requestFactoryMock.createRequest(any(URI.class), any())).thenReturn(requestMock); + + byte[] responseBody = "Image bytes".getBytes(Charset.defaultCharset()); + MockClientHttpResponse responseMock = new MockClientHttpResponse(responseBody, statusCode); + responseMock.getHeaders().setContentType(MediaType.IMAGE_PNG); + when(requestFactoryMock.createRequest( + new URI("testUriString"), org.springframework.http.HttpMethod.GET)) + .thenReturn(requestMock); + requestMock.setResponse(responseMock); + + return legendProcessorMock + .new IconTask(icon, 96, context, 1, null, requestFactoryMock, new MetricRegistry()); + } +}