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 f6c17d462..8ff512b78 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 { + @VisibleForTesting + final class IconTask implements Callable { private final URL icon; private final double iconDPI; @@ -351,20 +361,24 @@ private final class IconTask implements Callable { 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/processor/jasper/IconTaskTest.java b/core/src/test/java/org/mapfish/print/processor/jasper/IconTaskTest.java new file mode 100644 index 000000000..a6cb2abea --- /dev/null +++ b/core/src/test/java/org/mapfish/print/processor/jasper/IconTaskTest.java @@ -0,0 +1,75 @@ +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.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(); + 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()); + } +}