From 6b95cacdb6515555e40560a18bfa3e2da6c4a344 Mon Sep 17 00:00:00 2001 From: kszymankiewiczsd Date: Tue, 24 Feb 2026 15:03:54 +0100 Subject: [PATCH 1/3] Usage of global header for jasper reports --- .../report/service/JasperTemplateService.java | 159 +++++++++++++++++ .../report/web/JasperTemplateController.java | 28 ++- .../resources/reports/stock_on_hand.jrxml | 166 ++++++++++-------- .../service/JasperTemplateServiceTest.java | 142 ++++++++++++++- .../web/JasperTemplateControllerTest.java | 2 +- 5 files changed, 418 insertions(+), 79 deletions(-) diff --git a/src/main/java/org/openlmis/report/service/JasperTemplateService.java b/src/main/java/org/openlmis/report/service/JasperTemplateService.java index 34d89d8..dab32c3 100644 --- a/src/main/java/org/openlmis/report/service/JasperTemplateService.java +++ b/src/main/java/org/openlmis/report/service/JasperTemplateService.java @@ -28,16 +28,26 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.MissingResourceException; import java.util.Optional; +import java.util.Properties; +import java.util.ResourceBundle; import java.util.Set; import java.util.stream.Collectors; import javax.imageio.ImageIO; @@ -46,6 +56,9 @@ import net.sf.jasperreports.engine.JRParameter; import net.sf.jasperreports.engine.JasperCompileManager; import net.sf.jasperreports.engine.JasperReport; +import net.sf.jasperreports.engine.type.OrientationEnum; +import net.sf.jasperreports.engine.util.JRLoader; + import org.openlmis.report.domain.JasperTemplate; import org.openlmis.report.domain.JasperTemplateParameter; import org.openlmis.report.domain.JasperTemplateParameterDependency; @@ -72,6 +85,7 @@ public class JasperTemplateService { static final String REPORT_TYPE_PROPERTY = "reportType"; private static final String DEFAULT_REPORT_TYPE = "Consistency Report"; private static final String[] ALLOWED_FILETYPES = {"jrxml"}; + private static final String configPath = "/config/reports/"; @Autowired private JasperTemplateRepository jasperTemplateRepository; @@ -191,6 +205,151 @@ public Map mapReportImagesToTemplate(JasperTemplate templ return map; } + /** + * Gets locale for translation resource bundle parameters. + * + * @param userLocaleString the user locale string + * @return the locale bundle parameters + * @throws MalformedURLException the malformed url exception + */ + public Map getLocaleBundleParameters(JasperReport parentReport, + String userLocaleString) + throws MalformedURLException { + // validate if report requires resource bundle or not + String resourceBundleName = parentReport != null ? parentReport.getResourceBundle() : null; + if (resourceBundleName == null || resourceBundleName.trim().isEmpty()) { + return Collections.emptyMap(); + } + + Locale userLocale; + try { + // try to parse locale param else fallback to english + userLocale = new Locale.Builder().setLanguageTag(userLocaleString).build(); + } catch (Exception e) { + userLocale = Locale.ENGLISH; + } + Map parameters = new HashMap<>(); + File resourceBundleDir = new File(configPath + "resourceBundles"); + if (resourceBundleDir.exists() && resourceBundleDir.isDirectory()) { + URL[] urls = {resourceBundleDir.toURI().toURL()}; + + try (URLClassLoader externalLoader = new URLClassLoader(urls)) { + ResourceBundle externalBundle = ResourceBundle + .getBundle("report_translations", userLocale, externalLoader); + + parameters.put(JRParameter.REPORT_RESOURCE_BUNDLE, externalBundle); + parameters.put(JRParameter.REPORT_LOCALE, userLocale); + } catch (IOException | MissingResourceException e) { + // No translations bundle + return Collections.emptyMap(); + } + } + return parameters; + } + + /** + * Gets map subreport global header parameters. + * + * @param parentReport the parent report + * @return the map subreport global header parameters + * @throws JRException the jr exception + * @throws IOException the io exception + */ + public Map getMapSubreportGlobalHeaderParameters(JasperReport parentReport) + throws JRException, IOException, ReportingException { + // validate if report requires header or not + boolean needsHeader = parentReport != null && parentReport.getParameters() != null + && Arrays.stream(parentReport.getParameters()) + .anyMatch(param -> "headerTemplate".equals(param.getName())); + if (!needsHeader) { + return Collections.emptyMap(); + } + + File configDir = new File(configPath); + if (!configDir.exists() || !configDir.isDirectory()) { + // config directory does not exist + return Collections.emptyMap(); + } + + String headerName; + if (OrientationEnum.LANDSCAPE.equals(parentReport.getOrientationValue())) { + headerName = "GlobalHeaderLandscape"; + } else if (OrientationEnum.PORTRAIT.equals(parentReport.getOrientationValue())) { + headerName = "GlobalHeaderPortrait"; + } else { + // no orientation recognized + return Collections.emptyMap(); + } + + Map parameters = new HashMap<>(); + File headerFile = new File(configPath + headerName + ".jrxml"); + if (headerFile.exists()) { + try (InputStream is = Files.newInputStream(headerFile.toPath())) { + JasperReport globalHeader = JasperCompileManager.compileReport(is); + parameters.put("headerTemplate", globalHeader); + } catch (JRException | IOException e) { + throw new ReportingException(e, ERROR_REPORTING_FILE_INVALID); + } + } else { + return Collections.emptyMap(); + } + + parameters.putAll(injectDynamicHeaderParams()); + return parameters; + } + + /** + * Inject dynamic header params map. + * + * @return the map + * @throws IOException the io exception + */ + private Map injectDynamicHeaderParams() throws IOException { + Map parameters = new HashMap<>(); + File configFile = new File(configPath + "header_config.properties"); + + if (configFile.exists()) { + Properties dynamicProps = new Properties(); + try (InputStream is = Files.newInputStream(configFile.toPath())) { + dynamicProps.load(is); + } + + for (String key : dynamicProps.stringPropertyNames()) { + String value = dynamicProps.getProperty(key); + + if (key.endsWith("Image")) { + File imageFile = new File(configPath + value); + if (imageFile.exists()) { + parameters.put(key, imageFile.getAbsolutePath()); + } + } else { + parameters.put(key, value); + } + } + } + return parameters; + } + + /** + * Load report jasper report. + * + * @param jasperTemplate the jasper template + * @return the jasper report + * @throws ReportingException the reporting exception + */ + public JasperReport loadReport(JasperTemplate jasperTemplate) throws ReportingException { + if (jasperTemplate != null) { + try (InputStream is = new ByteArrayInputStream(jasperTemplate.getData())) { + return (JasperReport) JRLoader.loadObject(is); + } catch (JRException ex) { + throw new ReportingException(ex, ERROR_REPORTING_FILE_INVALID); + } catch (IOException ex) { + throw new ReportingException(ex, ERROR_REPORTING_IO, ex.getMessage()); + } + } + return null; + } + /** * Validate ".jrmxl" file and insert this template to database. * Throws reporting exception if an error occurs during file validation or parsing, diff --git a/src/main/java/org/openlmis/report/web/JasperTemplateController.java b/src/main/java/org/openlmis/report/web/JasperTemplateController.java index e695ec4..61ebbe0 100644 --- a/src/main/java/org/openlmis/report/web/JasperTemplateController.java +++ b/src/main/java/org/openlmis/report/web/JasperTemplateController.java @@ -18,6 +18,8 @@ import static org.apache.commons.lang3.BooleanUtils.isNotFalse; import static org.openlmis.report.i18n.JasperMessageKeys.ERROR_JASPER_TEMPLATE_NOT_FOUND; +import java.io.IOException; +import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -26,8 +28,12 @@ import java.util.List; import java.util.Map; import java.util.UUID; + import javax.servlet.http.HttpServletRequest; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperReport; + import org.openlmis.report.domain.JasperTemplate; import org.openlmis.report.dto.JasperTemplateDto; import org.openlmis.report.dto.external.referencedata.UserDto; @@ -52,6 +58,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; @@ -178,7 +185,8 @@ public void deleteTemplate(@PathVariable("id") UUID templateId) { @ResponseBody public ResponseEntity generateReport( HttpServletRequest request, @PathVariable("id") UUID templateId, - @PathVariable("format") String format) throws JasperReportViewException { + @PathVariable("format") String format, @RequestParam(defaultValue = "en") String locale) + throws JasperReportViewException { JasperTemplate template = jasperTemplateRepository.findById(templateId) .orElseThrow(() -> new NotFoundMessageException( new Message(ERROR_JASPER_TEMPLATE_NOT_FOUND, templateId))); @@ -198,6 +206,24 @@ public ResponseEntity generateReport( ); map.putAll(jasperTemplateService.mapReportImagesToTemplate(template)); + try { + JasperReport templateReport = jasperTemplateService.loadReport(template); + + try { + map.putAll(jasperTemplateService.getLocaleBundleParameters(templateReport, locale)); + } catch (MalformedURLException e) { + LOGGER.debug("Cannot load translation bundle for {}", template.getName()); + } + + try { + map.putAll(jasperTemplateService.getMapSubreportGlobalHeaderParameters(templateReport)); + } catch (ReportingException | JRException | IOException ex) { + LOGGER.debug("Cannot load GlobalHeaderTemplate for {}", template.getName()); + } + } catch (ReportingException e) { + LOGGER.debug("Cannot compile template {}", template.getName()); + } + map.put("format", format); map.put("dateTimeFormat", dateTimeFormat); map.put("dateFormat", dateFormat); diff --git a/src/main/resources/reports/stock_on_hand.jrxml b/src/main/resources/reports/stock_on_hand.jrxml index bc4bf7c..0f33c09 100644 --- a/src/main/resources/reports/stock_on_hand.jrxml +++ b/src/main/resources/reports/stock_on_hand.jrxml @@ -1,6 +1,6 @@ - - + + @@ -56,6 +56,7 @@ + - <band height="2" splitType="Stretch"/> + <band height="20" splitType="Stretch"> + <property name="com.jaspersoft.studio.unit.height" value="px"/> + </band> + - + - - + + - - - - + + + + - - + + @@ -248,13 +252,6 @@ GROUP BY - - - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + @@ -292,8 +306,8 @@ GROUP BY - - + + @@ -304,10 +318,10 @@ GROUP BY - - - - + + + + @@ -318,10 +332,10 @@ GROUP BY - - - - + + + + @@ -332,10 +346,10 @@ GROUP BY - - - - + + + + @@ -346,10 +360,10 @@ GROUP BY - - - - + + + + @@ -360,10 +374,10 @@ GROUP BY - - - - + + + + @@ -374,10 +388,10 @@ GROUP BY - - - - + + + + @@ -388,10 +402,10 @@ GROUP BY - - - - + + + + @@ -402,10 +416,10 @@ GROUP BY - - - - + + + + @@ -416,10 +430,10 @@ GROUP BY - - - - + + + + @@ -430,10 +444,10 @@ GROUP BY - - - - + + + + @@ -444,10 +458,10 @@ GROUP BY - - - - + + + + @@ -458,8 +472,8 @@ GROUP BY - - + + @@ -610,21 +624,21 @@ GROUP BY - + - - + + - - + + diff --git a/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java b/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java index 1ee0ab6..b176020 100644 --- a/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java +++ b/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java @@ -46,17 +46,21 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutputStream; +import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.ResourceBundle; import java.util.Set; import java.util.UUID; import javax.imageio.ImageIO; @@ -66,6 +70,8 @@ import net.sf.jasperreports.engine.JRPropertiesMap; import net.sf.jasperreports.engine.JasperCompileManager; import net.sf.jasperreports.engine.JasperReport; +import net.sf.jasperreports.engine.type.OrientationEnum; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -96,7 +102,12 @@ @RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(BlockJUnit4ClassRunner.class) -@PrepareForTest({JasperTemplateService.class, JasperCompileManager.class}) +@PrepareForTest({ + JasperTemplateService.class, + JasperCompileManager.class, + ResourceBundle.class, + java.nio.file.Files.class +}) @SuppressWarnings("PMD.TooManyMethods") public class JasperTemplateServiceTest { @@ -594,6 +605,135 @@ public void mapReportImagesToTemplateShouldReturnMatchingImages() convertImageToByteArray(resultMap.get(IMAGE_NAME)))); } + @Test + public void getLocaleBundleShouldReturnEmptyMapIfNoResourceBundleProperty() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + when(parentReport.getResourceBundle()).thenReturn(null); + + Map result = jasperTemplateService + .getLocaleBundleParameters(parentReport, "en"); + + assertTrue(result.isEmpty()); + } + + @Test + public void getLocaleBundleShouldReturnMapWithBundleAndLocale() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + when(parentReport.getResourceBundle()).thenReturn("report_translations"); + + // Mock the Config Directory + File mockDir = mock(File.class); + whenNew(File.class).withArguments("/config/reports/resourceBundles").thenReturn(mockDir); + when(mockDir.exists()).thenReturn(true); + when(mockDir.isDirectory()).thenReturn(true); + when(mockDir.toURI()).thenReturn(new java.net.URI("file://dummy")); + + ResourceBundle mockBundle = mock(ResourceBundle.class); + mockStatic(ResourceBundle.class); + when(ResourceBundle.getBundle(eq("report_translations"), any(Locale.class), + any(URLClassLoader.class))).thenReturn(mockBundle); + + Map result = jasperTemplateService + .getLocaleBundleParameters(parentReport, "fr"); + + assertEquals(2, result.size()); + assertEquals(mockBundle, result.get(JRParameter.REPORT_RESOURCE_BUNDLE)); + assertEquals(new Locale.Builder().setLanguageTag("fr").build(), + result.get(JRParameter.REPORT_LOCALE)); + } + + @Test + public void getGlobalHeaderShouldReturnEmptyMapIfNoHeaderParam() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter param = mock(JRParameter.class); + when(param.getName()).thenReturn("someOtherParam"); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{param}); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertTrue(result.isEmpty()); + } + + @Test + public void getGlobalHeaderShouldReturnEmptyMapIfOrientationNotRecognized() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn("headerTemplate"); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + + // Unrecognized orientation + when(parentReport.getOrientationValue()).thenReturn(null); + + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments("/config/reports/").thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(true); + when(mockConfigDir.isDirectory()).thenReturn(true); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertTrue(result.isEmpty()); + } + + @Test + public void getGlobalHeaderShouldReturnCompiledHeaderAndDynamicParams() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn("headerTemplate"); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.LANDSCAPE); + + // Mock the Config Directory + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments("/config/reports/").thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(true); + when(mockConfigDir.isDirectory()).thenReturn(true); + + File tempJrxml = File.createTempFile("GlobalHeaderLandscape", ".jrxml"); + tempJrxml.deleteOnExit(); + + File tempPropsFile = File.createTempFile("header_config", ".properties"); + tempPropsFile.deleteOnExit(); + + try (java.io.FileOutputStream fos = new java.io.FileOutputStream(tempPropsFile)) { + fos.write("title=Test Ministry\nlogoImage=logo.png".getBytes()); + } + + File mockHeaderFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/GlobalHeaderLandscape.jrxml") + .thenReturn(mockHeaderFile); + when(mockHeaderFile.exists()).thenReturn(true); + + when(mockHeaderFile.toPath()).thenReturn(tempJrxml.toPath()); + + JasperReport mockCompiledHeader = mock(JasperReport.class); + mockStatic(JasperCompileManager.class); + + when(JasperCompileManager.compileReport(any(InputStream.class))).thenReturn(mockCompiledHeader); + + File mockConfigFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/header_config.properties") + .thenReturn(mockConfigFile); + when(mockConfigFile.exists()).thenReturn(true); + + when(mockConfigFile.toPath()).thenReturn(tempPropsFile.toPath()); + + // Image File check + File mockImageFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/logo.png").thenReturn(mockImageFile); + when(mockImageFile.exists()).thenReturn(true); + when(mockImageFile.getAbsolutePath()).thenReturn("/config/reports/logo.png"); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertEquals(3, result.size()); + assertEquals(mockCompiledHeader, result.get("headerTemplate")); + assertEquals("Test Ministry", result.get("title")); + assertEquals("/config/reports/logo.png", result.get("logoImage")); + } + private byte[] convertImageToByteArray(BufferedImage image) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(image, "png", os); diff --git a/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java b/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java index fc1521c..9c01fba 100644 --- a/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java +++ b/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java @@ -124,7 +124,7 @@ public void reportShouldHaveCorrectNameAndContentTypeInHeaders() MockHttpServletRequest request = new MockHttpServletRequest(); ResponseEntity response = jasperTemplateController.generateReport(request, - jasperTemplate.getId(), "xlsx"); + jasperTemplate.getId(), "xlsx", "en"); assertTrue(response.getHeaders().toString().contains("name.xlsx")); assertTrue(response.getHeaders().toString().contains("Content-Type:\"application/" + "vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8\"")); From d3827f7bf6b6ff15b6eef1cbe86d3c6675ba3805 Mon Sep 17 00:00:00 2001 From: kszymankiewiczsd Date: Thu, 26 Feb 2026 12:38:35 +0100 Subject: [PATCH 2/3] GlobalHeader tests --- .../report/service/JasperTemplateService.java | 16 +- .../report/web/JasperTemplateController.java | 20 +- .../service/JasperTemplateServiceTest.java | 359 +++++++++++++++++- .../web/JasperTemplateControllerTest.java | 7 + 4 files changed, 366 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/openlmis/report/service/JasperTemplateService.java b/src/main/java/org/openlmis/report/service/JasperTemplateService.java index dab32c3..19826df 100644 --- a/src/main/java/org/openlmis/report/service/JasperTemplateService.java +++ b/src/main/java/org/openlmis/report/service/JasperTemplateService.java @@ -85,7 +85,7 @@ public class JasperTemplateService { static final String REPORT_TYPE_PROPERTY = "reportType"; private static final String DEFAULT_REPORT_TYPE = "Consistency Report"; private static final String[] ALLOWED_FILETYPES = {"jrxml"}; - private static final String configPath = "/config/reports/"; + private static final String CONFIG_PATH = "/config/reports/"; @Autowired private JasperTemplateRepository jasperTemplateRepository; @@ -229,7 +229,7 @@ public Map getLocaleBundleParameters(JasperReport parentReport, userLocale = Locale.ENGLISH; } Map parameters = new HashMap<>(); - File resourceBundleDir = new File(configPath + "resourceBundles"); + File resourceBundleDir = new File(CONFIG_PATH + "resourceBundles"); if (resourceBundleDir.exists() && resourceBundleDir.isDirectory()) { URL[] urls = {resourceBundleDir.toURI().toURL()}; @@ -256,7 +256,7 @@ public Map getLocaleBundleParameters(JasperReport parentReport, * @throws IOException the io exception */ public Map getMapSubreportGlobalHeaderParameters(JasperReport parentReport) - throws JRException, IOException, ReportingException { + throws JRException, IOException { // validate if report requires header or not boolean needsHeader = parentReport != null && parentReport.getParameters() != null && Arrays.stream(parentReport.getParameters()) @@ -265,7 +265,7 @@ public Map getMapSubreportGlobalHeaderParameters(JasperReport pa return Collections.emptyMap(); } - File configDir = new File(configPath); + File configDir = new File(CONFIG_PATH); if (!configDir.exists() || !configDir.isDirectory()) { // config directory does not exist return Collections.emptyMap(); @@ -282,13 +282,11 @@ public Map getMapSubreportGlobalHeaderParameters(JasperReport pa } Map parameters = new HashMap<>(); - File headerFile = new File(configPath + headerName + ".jrxml"); + File headerFile = new File(CONFIG_PATH + headerName + ".jrxml"); if (headerFile.exists()) { try (InputStream is = Files.newInputStream(headerFile.toPath())) { JasperReport globalHeader = JasperCompileManager.compileReport(is); parameters.put("headerTemplate", globalHeader); - } catch (JRException | IOException e) { - throw new ReportingException(e, ERROR_REPORTING_FILE_INVALID); } } else { return Collections.emptyMap(); @@ -306,7 +304,7 @@ public Map getMapSubreportGlobalHeaderParameters(JasperReport pa */ private Map injectDynamicHeaderParams() throws IOException { Map parameters = new HashMap<>(); - File configFile = new File(configPath + "header_config.properties"); + File configFile = new File(CONFIG_PATH + "header_config.properties"); if (configFile.exists()) { Properties dynamicProps = new Properties(); @@ -318,7 +316,7 @@ private Map injectDynamicHeaderParams() throws IOException { String value = dynamicProps.getProperty(key); if (key.endsWith("Image")) { - File imageFile = new File(configPath + value); + File imageFile = new File(CONFIG_PATH + value); if (imageFile.exists()) { parameters.put(key, imageFile.getAbsolutePath()); } diff --git a/src/main/java/org/openlmis/report/web/JasperTemplateController.java b/src/main/java/org/openlmis/report/web/JasperTemplateController.java index 61ebbe0..0aa6399 100644 --- a/src/main/java/org/openlmis/report/web/JasperTemplateController.java +++ b/src/main/java/org/openlmis/report/web/JasperTemplateController.java @@ -185,7 +185,7 @@ public void deleteTemplate(@PathVariable("id") UUID templateId) { @ResponseBody public ResponseEntity generateReport( HttpServletRequest request, @PathVariable("id") UUID templateId, - @PathVariable("format") String format, @RequestParam(defaultValue = "en") String locale) + @PathVariable("format") String format, @RequestParam(defaultValue = "en") String lang) throws JasperReportViewException { JasperTemplate template = jasperTemplateRepository.findById(templateId) .orElseThrow(() -> new NotFoundMessageException( @@ -208,20 +208,14 @@ public ResponseEntity generateReport( try { JasperReport templateReport = jasperTemplateService.loadReport(template); - - try { - map.putAll(jasperTemplateService.getLocaleBundleParameters(templateReport, locale)); - } catch (MalformedURLException e) { - LOGGER.debug("Cannot load translation bundle for {}", template.getName()); - } - - try { - map.putAll(jasperTemplateService.getMapSubreportGlobalHeaderParameters(templateReport)); - } catch (ReportingException | JRException | IOException ex) { - LOGGER.debug("Cannot load GlobalHeaderTemplate for {}", template.getName()); - } + map.putAll(jasperTemplateService.getLocaleBundleParameters(templateReport, lang)); + map.putAll(jasperTemplateService.getMapSubreportGlobalHeaderParameters(templateReport)); } catch (ReportingException e) { LOGGER.debug("Cannot compile template {}", template.getName()); + } catch (MalformedURLException e) { + LOGGER.debug("Cannot load translation bundle for {}", template.getName()); + } catch (JRException | IOException ex) { + LOGGER.debug("Cannot load GlobalHeaderTemplate for {}", template.getName()); } map.put("format", format); diff --git a/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java b/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java index b176020..1456c2a 100644 --- a/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java +++ b/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java @@ -21,6 +21,7 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasProperty; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.BDDMockito.given; @@ -59,18 +60,22 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.MissingResourceException; import java.util.Optional; import java.util.ResourceBundle; import java.util.Set; import java.util.UUID; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; + +import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRExpression; import net.sf.jasperreports.engine.JRParameter; import net.sf.jasperreports.engine.JRPropertiesMap; import net.sf.jasperreports.engine.JasperCompileManager; import net.sf.jasperreports.engine.JasperReport; import net.sf.jasperreports.engine.type.OrientationEnum; +import net.sf.jasperreports.engine.util.JRLoader; import org.junit.Before; import org.junit.Rule; @@ -106,6 +111,7 @@ JasperTemplateService.class, JasperCompileManager.class, ResourceBundle.class, + JRLoader.class, java.nio.file.Files.class }) @SuppressWarnings("PMD.TooManyMethods") @@ -139,6 +145,14 @@ public class JasperTemplateServiceTest { private static final String PARAM3 = "param3"; private static final String PARAM4 = "param4"; private static final String IMAGE_NAME = "image"; + private static final String RESOURCE_BUNDLE_NAME = "report_translations"; + private static final String RESOURCE_BUNDLE_PATH = "/config/reports/resourceBundles"; + private static final String HEADER_PARAM_NAME = "headerTemplate"; + private static final String CONFIG_PATH_CONST = "/config/reports/"; + private static final String JRXML_EXTENSION = ".jrxml"; + private static final String HEADER_CONFIG_PROPERTIES = "/config/reports/header_config.properties"; + private static final String GLOBAL_HEADER_LANDSCAPE = "GlobalHeaderLandscape"; + private static final String GLOBAL_HEADER_PORTRAIT = "GlobalHeaderPortrait"; private HttpServletRequest request; private JasperTemplate template; @@ -606,31 +620,75 @@ public void mapReportImagesToTemplateShouldReturnMatchingImages() } @Test - public void getLocaleBundleShouldReturnEmptyMapIfNoResourceBundleProperty() throws Exception { + public void getLocaleBundleShouldReturnEmptyMapForInvalidResourceBundleNames() throws Exception { + assertTrue(jasperTemplateService.getLocaleBundleParameters(null, "en").isEmpty()); + JasperReport parentReport = mock(JasperReport.class); + when(parentReport.getResourceBundle()).thenReturn(null); + assertTrue(jasperTemplateService.getLocaleBundleParameters(parentReport, "en").isEmpty()); - Map result = jasperTemplateService - .getLocaleBundleParameters(parentReport, "en"); + // 3. Covers: resourceBundleName.isEmpty() + when(parentReport.getResourceBundle()).thenReturn(""); + assertTrue(jasperTemplateService.getLocaleBundleParameters(parentReport, "en").isEmpty()); - assertTrue(result.isEmpty()); + // 4. Covers: resourceBundleName.trim().isEmpty() + when(parentReport.getResourceBundle()).thenReturn(" "); + assertTrue(jasperTemplateService.getLocaleBundleParameters(parentReport, "en").isEmpty()); + } + + @Test + public void getLocaleBundleShouldReturnEmptyMapIfResourceBundleDirectoryDoesNotExist() + throws Exception { + JasperReport parentReport = mock(JasperReport.class); + when(parentReport.getResourceBundle()).thenReturn(RESOURCE_BUNDLE_NAME); + + File mockDir = mock(File.class); + whenNew(File.class).withArguments(RESOURCE_BUNDLE_PATH).thenReturn(mockDir); + + when(mockDir.exists()).thenReturn(false); + assertTrue(jasperTemplateService.getLocaleBundleParameters(parentReport, "en").isEmpty()); + + when(mockDir.exists()).thenReturn(true); + when(mockDir.isDirectory()).thenReturn(false); + assertTrue(jasperTemplateService.getLocaleBundleParameters(parentReport, "en").isEmpty()); + } + + @Test + public void getLocaleBundleShouldReturnEmptyMapIfTranslationBundleIsMissingFromDisk() + throws Exception { + JasperReport parentReport = mock(JasperReport.class); + when(parentReport.getResourceBundle()).thenReturn(RESOURCE_BUNDLE_NAME); + + File mockDir = mock(File.class); + whenNew(File.class).withArguments(RESOURCE_BUNDLE_PATH).thenReturn(mockDir); + when(mockDir.exists()).thenReturn(true); + when(mockDir.isDirectory()).thenReturn(true); + when(mockDir.toURI()).thenReturn(new java.net.URI("file://dummy")); + + mockStatic(ResourceBundle.class); + + when(ResourceBundle.getBundle(anyString(), any(Locale.class), any(URLClassLoader.class))) + .thenThrow(new MissingResourceException("Missing resource exception occurred", + "ResourceBundle", "key")); + assertTrue(jasperTemplateService.getLocaleBundleParameters(parentReport, "en").isEmpty()); } @Test public void getLocaleBundleShouldReturnMapWithBundleAndLocale() throws Exception { JasperReport parentReport = mock(JasperReport.class); - when(parentReport.getResourceBundle()).thenReturn("report_translations"); + when(parentReport.getResourceBundle()).thenReturn(RESOURCE_BUNDLE_NAME); // Mock the Config Directory File mockDir = mock(File.class); - whenNew(File.class).withArguments("/config/reports/resourceBundles").thenReturn(mockDir); + whenNew(File.class).withArguments(RESOURCE_BUNDLE_PATH).thenReturn(mockDir); when(mockDir.exists()).thenReturn(true); when(mockDir.isDirectory()).thenReturn(true); when(mockDir.toURI()).thenReturn(new java.net.URI("file://dummy")); ResourceBundle mockBundle = mock(ResourceBundle.class); mockStatic(ResourceBundle.class); - when(ResourceBundle.getBundle(eq("report_translations"), any(Locale.class), + when(ResourceBundle.getBundle(eq(RESOURCE_BUNDLE_NAME), any(Locale.class), any(URLClassLoader.class))).thenReturn(mockBundle); Map result = jasperTemplateService @@ -642,6 +700,158 @@ public void getLocaleBundleShouldReturnMapWithBundleAndLocale() throws Exception result.get(JRParameter.REPORT_LOCALE)); } + @Test + public void getLocaleBundleShouldFallbackToEnglishForInvalidLocale() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + when(parentReport.getResourceBundle()).thenReturn(RESOURCE_BUNDLE_NAME); + + File mockDir = mock(File.class); + whenNew(File.class).withArguments(RESOURCE_BUNDLE_PATH).thenReturn(mockDir); + when(mockDir.exists()).thenReturn(true); + when(mockDir.isDirectory()).thenReturn(true); + when(mockDir.toURI()).thenReturn(new java.net.URI("file://dummy")); + + ResourceBundle mockBundle = mock(ResourceBundle.class); + mockStatic(ResourceBundle.class); + when(ResourceBundle.getBundle(eq(RESOURCE_BUNDLE_NAME), any(Locale.class), + any(URLClassLoader.class))).thenReturn(mockBundle); + + Map result = jasperTemplateService + .getLocaleBundleParameters(parentReport, "invalid_locale"); + + assertEquals(Locale.ENGLISH, result.get(JRParameter.REPORT_LOCALE)); + } + + @Test + public void loadReportShouldReturnNullForNullTemplate() throws Exception { + JasperReport result = jasperTemplateService.loadReport(null); + assertNull(result); + } + + @Test + public void loadReportShouldSuccessfullyLoadValidTemplate() throws Exception { + JasperTemplate template = mock(JasperTemplate.class); + byte[] templateData = new byte[]{1, 2, 3}; + when(template.getData()).thenReturn(templateData); + + JasperReport mockReport = mock(JasperReport.class); + mockStatic(JRLoader.class); + when(JRLoader.loadObject(any(InputStream.class))).thenReturn(mockReport); + + JasperReport result = jasperTemplateService.loadReport(template); + + assertEquals(mockReport, result); + } + + @Test + public void loadReportShouldThrowExceptionForInvalidReportFile() throws Exception { + JasperTemplate template = mock(JasperTemplate.class); + byte[] templateData = new byte[]{1, 2, 3}; + when(template.getData()).thenReturn(templateData); + + mockStatic(JRLoader.class); + when(JRLoader.loadObject(any(InputStream.class))).thenThrow(new JRException("Invalid file")); + + expectedException.expect(ReportingException.class); + expectedException.expectMessage(ERROR_REPORTING_FILE_INVALID); + + jasperTemplateService.loadReport(template); + } + + @Test + public void getGlobalHeaderShouldReturnEmptyMapWhenHeaderConfigFileDoesNotExist() + throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.PORTRAIT); + + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(true); + when(mockConfigDir.isDirectory()).thenReturn(true); + + File tempJrxml = File.createTempFile(GLOBAL_HEADER_PORTRAIT, JRXML_EXTENSION); + tempJrxml.deleteOnExit(); + + File mockHeaderFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/GlobalHeaderPortrait.jrxml") + .thenReturn(mockHeaderFile); + when(mockHeaderFile.exists()).thenReturn(true); + when(mockHeaderFile.toPath()).thenReturn(tempJrxml.toPath()); + + JasperReport mockCompiledHeader = mock(JasperReport.class); + mockStatic(JasperCompileManager.class); + when(JasperCompileManager.compileReport(any(InputStream.class))) + .thenReturn(mockCompiledHeader); + + File mockConfigFile = mock(File.class); + whenNew(File.class).withArguments(HEADER_CONFIG_PROPERTIES) + .thenReturn(mockConfigFile); + when(mockConfigFile.exists()).thenReturn(false); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertEquals(1, result.size()); + assertEquals(mockCompiledHeader, result.get(HEADER_PARAM_NAME)); + } + + @Test + public void getGlobalHeaderShouldSkipImageParamsWhenImageFileDoesNotExist() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.PORTRAIT); + + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(true); + when(mockConfigDir.isDirectory()).thenReturn(true); + + File tempJrxml = File.createTempFile(GLOBAL_HEADER_PORTRAIT, JRXML_EXTENSION); + tempJrxml.deleteOnExit(); + + File tempPropsFile = File.createTempFile("header_config", ".properties"); + tempPropsFile.deleteOnExit(); + + try (java.io.FileOutputStream fos = new java.io.FileOutputStream(tempPropsFile)) { + fos.write("title=Test Title\nlogoImage=nonexistent.png".getBytes()); + } + + File mockHeaderFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/GlobalHeaderPortrait.jrxml") + .thenReturn(mockHeaderFile); + when(mockHeaderFile.exists()).thenReturn(true); + when(mockHeaderFile.toPath()).thenReturn(tempJrxml.toPath()); + + JasperReport mockCompiledHeader = mock(JasperReport.class); + mockStatic(JasperCompileManager.class); + when(JasperCompileManager.compileReport(any(InputStream.class))) + .thenReturn(mockCompiledHeader); + + File mockConfigFile = mock(File.class); + whenNew(File.class).withArguments(HEADER_CONFIG_PROPERTIES) + .thenReturn(mockConfigFile); + when(mockConfigFile.exists()).thenReturn(true); + when(mockConfigFile.toPath()).thenReturn(tempPropsFile.toPath()); + + File mockImageFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/nonexistent.png") + .thenReturn(mockImageFile); + when(mockImageFile.exists()).thenReturn(false); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertEquals(2, result.size()); + assertEquals(mockCompiledHeader, result.get(HEADER_PARAM_NAME)); + assertEquals("Test Title", result.get("title")); + assertNull(result.get("logoImage")); + } + @Test public void getGlobalHeaderShouldReturnEmptyMapIfNoHeaderParam() throws Exception { JasperReport parentReport = mock(JasperReport.class); @@ -655,18 +865,139 @@ public void getGlobalHeaderShouldReturnEmptyMapIfNoHeaderParam() throws Exceptio assertTrue(result.isEmpty()); } + @Test + public void getGlobalHeaderShouldReturnEmptyMapForNullParentReport() throws Exception { + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(null); + + assertTrue(result.isEmpty()); + } + + @Test + public void getGlobalHeaderShouldReturnEmptyMapIfParametersAreNull() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + when(parentReport.getParameters()).thenReturn(null); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertTrue(result.isEmpty()); + } + + @Test + public void getGlobalHeaderShouldReturnEmptyMapIfConfigDirectoryDoesNotExist() + throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.PORTRAIT); + + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(false); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertTrue(result.isEmpty()); + } + + @Test + public void getGlobalHeaderShouldReturnEmptyMapIfConfigDirectoryIsNotADirectory() + throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.PORTRAIT); + + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(true); + when(mockConfigDir.isDirectory()).thenReturn(false); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertTrue(result.isEmpty()); + } + + @Test + public void getGlobalHeaderShouldReturnEmptyMapIfHeaderFileDoesNotExist() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.PORTRAIT); + + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(true); + when(mockConfigDir.isDirectory()).thenReturn(true); + + File mockHeaderFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/GlobalHeaderPortrait.jrxml") + .thenReturn(mockHeaderFile); + when(mockHeaderFile.exists()).thenReturn(false); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertTrue(result.isEmpty()); + } + + @Test + public void getGlobalHeaderShouldUseLandscapeHeaderForLandscapeOrientation() throws Exception { + JasperReport parentReport = mock(JasperReport.class); + JRParameter headerParam = mock(JRParameter.class); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); + when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); + when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.LANDSCAPE); + + File mockConfigDir = mock(File.class); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); + when(mockConfigDir.exists()).thenReturn(true); + when(mockConfigDir.isDirectory()).thenReturn(true); + + File tempJrxml = File.createTempFile(GLOBAL_HEADER_LANDSCAPE, JRXML_EXTENSION); + tempJrxml.deleteOnExit(); + + File mockHeaderFile = mock(File.class); + whenNew(File.class).withArguments("/config/reports/GlobalHeaderLandscape.jrxml") + .thenReturn(mockHeaderFile); + when(mockHeaderFile.exists()).thenReturn(true); + when(mockHeaderFile.toPath()).thenReturn(tempJrxml.toPath()); + + JasperReport mockCompiledHeader = mock(JasperReport.class); + mockStatic(JasperCompileManager.class); + when(JasperCompileManager.compileReport(any(InputStream.class))) + .thenReturn(mockCompiledHeader); + + File mockConfigFile = mock(File.class); + whenNew(File.class).withArguments(HEADER_CONFIG_PROPERTIES) + .thenReturn(mockConfigFile); + when(mockConfigFile.exists()).thenReturn(false); + + Map result = jasperTemplateService + .getMapSubreportGlobalHeaderParameters(parentReport); + + assertEquals(1, result.size()); + assertEquals(mockCompiledHeader, result.get(HEADER_PARAM_NAME)); + } + @Test public void getGlobalHeaderShouldReturnEmptyMapIfOrientationNotRecognized() throws Exception { JasperReport parentReport = mock(JasperReport.class); JRParameter headerParam = mock(JRParameter.class); - when(headerParam.getName()).thenReturn("headerTemplate"); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); // Unrecognized orientation when(parentReport.getOrientationValue()).thenReturn(null); File mockConfigDir = mock(File.class); - whenNew(File.class).withArguments("/config/reports/").thenReturn(mockConfigDir); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); when(mockConfigDir.exists()).thenReturn(true); when(mockConfigDir.isDirectory()).thenReturn(true); @@ -680,17 +1011,17 @@ public void getGlobalHeaderShouldReturnEmptyMapIfOrientationNotRecognized() thro public void getGlobalHeaderShouldReturnCompiledHeaderAndDynamicParams() throws Exception { JasperReport parentReport = mock(JasperReport.class); JRParameter headerParam = mock(JRParameter.class); - when(headerParam.getName()).thenReturn("headerTemplate"); + when(headerParam.getName()).thenReturn(HEADER_PARAM_NAME); when(parentReport.getParameters()).thenReturn(new JRParameter[]{headerParam}); when(parentReport.getOrientationValue()).thenReturn(OrientationEnum.LANDSCAPE); // Mock the Config Directory File mockConfigDir = mock(File.class); - whenNew(File.class).withArguments("/config/reports/").thenReturn(mockConfigDir); + whenNew(File.class).withArguments(CONFIG_PATH_CONST).thenReturn(mockConfigDir); when(mockConfigDir.exists()).thenReturn(true); when(mockConfigDir.isDirectory()).thenReturn(true); - File tempJrxml = File.createTempFile("GlobalHeaderLandscape", ".jrxml"); + File tempJrxml = File.createTempFile(GLOBAL_HEADER_LANDSCAPE, JRXML_EXTENSION); tempJrxml.deleteOnExit(); File tempPropsFile = File.createTempFile("header_config", ".properties"); @@ -713,7 +1044,7 @@ public void getGlobalHeaderShouldReturnCompiledHeaderAndDynamicParams() throws E when(JasperCompileManager.compileReport(any(InputStream.class))).thenReturn(mockCompiledHeader); File mockConfigFile = mock(File.class); - whenNew(File.class).withArguments("/config/reports/header_config.properties") + whenNew(File.class).withArguments(HEADER_CONFIG_PROPERTIES) .thenReturn(mockConfigFile); when(mockConfigFile.exists()).thenReturn(true); @@ -729,7 +1060,7 @@ public void getGlobalHeaderShouldReturnCompiledHeaderAndDynamicParams() throws E .getMapSubreportGlobalHeaderParameters(parentReport); assertEquals(3, result.size()); - assertEquals(mockCompiledHeader, result.get("headerTemplate")); + assertEquals(mockCompiledHeader, result.get(HEADER_PARAM_NAME)); assertEquals("Test Ministry", result.get("title")); assertEquals("/config/reports/logo.png", result.get("logoImage")); } diff --git a/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java b/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java index 9c01fba..7097357 100644 --- a/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java +++ b/src/test/java/org/openlmis/report/web/JasperTemplateControllerTest.java @@ -128,6 +128,13 @@ public void reportShouldHaveCorrectNameAndContentTypeInHeaders() assertTrue(response.getHeaders().toString().contains("name.xlsx")); assertTrue(response.getHeaders().toString().contains("Content-Type:\"application/" + "vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8\"")); + + request = new MockHttpServletRequest(); + response = jasperTemplateController.generateReport(request, + jasperTemplate.getId(), "xlsx", null); + assertTrue(response.getHeaders().toString().contains("name.xlsx")); + assertTrue(response.getHeaders().toString().contains("Content-Type:\"application/" + + "vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8\"")); } } From b8ddb8b32845df0c87057ba10234cdeb0a4eeeea Mon Sep 17 00:00:00 2001 From: kszymankiewiczsd Date: Thu, 26 Feb 2026 13:22:30 +0100 Subject: [PATCH 3/3] Usage of class variable for JasperTemplate --- .../openlmis/report/service/JasperTemplateServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java b/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java index 1456c2a..046c8cc 100644 --- a/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java +++ b/src/test/java/org/openlmis/report/service/JasperTemplateServiceTest.java @@ -730,7 +730,7 @@ public void loadReportShouldReturnNullForNullTemplate() throws Exception { @Test public void loadReportShouldSuccessfullyLoadValidTemplate() throws Exception { - JasperTemplate template = mock(JasperTemplate.class); + template = mock(JasperTemplate.class); byte[] templateData = new byte[]{1, 2, 3}; when(template.getData()).thenReturn(templateData); @@ -745,7 +745,7 @@ public void loadReportShouldSuccessfullyLoadValidTemplate() throws Exception { @Test public void loadReportShouldThrowExceptionForInvalidReportFile() throws Exception { - JasperTemplate template = mock(JasperTemplate.class); + template = mock(JasperTemplate.class); byte[] templateData = new byte[]{1, 2, 3}; when(template.getData()).thenReturn(templateData);