This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch WW-5734-tomcat-it in repository https://gitbox.apache.org/repos/asf/struts.git
commit 7e28be30c9f1022c1e75c65a3af46d94d53a9260 Author: Lukasz Lenart <[email protected]> AuthorDate: Sat Sep 12 14:37:47 2026 +0200 WW-5734 test(jasperreports7): run the plugin end-to-end on an embedded Tomcat The plugin had never been exercised outside Spring's mock response, which is how WW-5731, WW-5732 and WW-5733 went unnoticed since 7.1.0. The showcase cannot host an example because JasperReports is LGPL and the showcase WAR ships in the release assembly. JasperReport7TomcatTest boots Struts on tomcat-embed-core (test scope), compiles the existing simple.jrxml into the webapp's docBase and asserts that a real HTTP request returns a non-empty body of the right content type for each of the six bundled formats. Against the providers as they were before WW-5733 all six assertions fail with an empty body. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> --- plugins/jasperreports7/pom.xml | 7 + .../tomcat/JasperReport7TomcatTest.java | 148 +++++++++++++++++++++ .../views/jasperreports7/tomcat/ReportAction.java | 47 +++++++ .../src/test/resources/struts-tomcat.xml | 36 +++++ 4 files changed, 238 insertions(+) diff --git a/plugins/jasperreports7/pom.xml b/plugins/jasperreports7/pom.xml index cb0467305..00017e256 100644 --- a/plugins/jasperreports7/pom.xml +++ b/plugins/jasperreports7/pom.xml @@ -34,6 +34,7 @@ <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jasperreports7.version>7.0.7</jasperreports7.version> + <tomcat-embed.version>10.1.55</tomcat-embed.version> </properties> <dependencies> @@ -78,5 +79,11 @@ <artifactId>easymock</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + <version>${tomcat-embed.version}</version> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/plugins/jasperreports7/src/test/java/org/apache/struts2/views/jasperreports7/tomcat/JasperReport7TomcatTest.java b/plugins/jasperreports7/src/test/java/org/apache/struts2/views/jasperreports7/tomcat/JasperReport7TomcatTest.java new file mode 100644 index 000000000..bf1579981 --- /dev/null +++ b/plugins/jasperreports7/src/test/java/org/apache/struts2/views/jasperreports7/tomcat/JasperReport7TomcatTest.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.views.jasperreports7.tomcat; + +import net.sf.jasperreports.engine.JasperCompileManager; +import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; +import org.apache.catalina.startup.Tomcat; +import org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter; +import org.apache.struts2.util.ClassLoaderUtil; +import org.apache.tomcat.util.descriptor.web.FilterDef; +import org.apache.tomcat.util.descriptor.web.FilterMap; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.net.URI; +import java.net.URL; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Runs the plugin on a real servlet container: the mock response used by the other tests + * keeps accepting writes after the stream is closed, a container does not. + */ +public class JasperReport7TomcatTest { + + private static Tomcat tomcat; + private static String baseUrl; + + @BeforeClass + public static void startTomcat() throws Exception { + Path baseDir = Files.createTempDirectory(Files.createDirectories(Path.of("target")), "tomcat").toAbsolutePath(); + Path docBase = Files.createDirectories(baseDir.resolve("webapp")); + Path reports = Files.createDirectories(docBase.resolve("reports")); + URL jrxml = ClassLoaderUtil.getResource("org/apache/struts2/views/jasperreports7/simple.jrxml", JasperReport7TomcatTest.class); + JasperCompileManager.compileReportToFile(Path.of(jrxml.toURI()).toString(), reports.resolve("simple.jasper").toString()); + + tomcat = new Tomcat(); + tomcat.setBaseDir(baseDir.toString()); + tomcat.setPort(0); + tomcat.getConnector().setProperty("address", "127.0.0.1"); + + Context context = tomcat.addContext("", docBase.toString()); + Tomcat.addServlet(context, "default", new DefaultServlet()); + context.addServletMappingDecoded("/", "default"); + FilterDef filterDef = new FilterDef(); + filterDef.setFilterName("struts"); + filterDef.setFilterClass(StrutsPrepareAndExecuteFilter.class.getName()); + filterDef.addInitParameter("config", "struts-default.xml,struts-plugin.xml,struts-tomcat.xml"); + context.addFilterDef(filterDef); + FilterMap filterMap = new FilterMap(); + filterMap.setFilterName("struts"); + filterMap.addURLPattern("/*"); + context.addFilterMap(filterMap); + + tomcat.start(); + baseUrl = "http://127.0.0.1:" + tomcat.getConnector().getLocalPort(); + } + + @AfterClass + public static void stopTomcat() throws Exception { + if (tomcat != null) { + tomcat.stop(); + tomcat.destroy(); + } + } + + @Test + public void exportsCsv() throws Exception { + HttpResponse<byte[]> response = report("csv"); + + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.headers().firstValue("Content-Type")).hasValueSatisfying(type -> assertThat(type).startsWith("text/csv")); + assertThat(new String(response.body())).contains("Tomcat Report").contains("Hello Foo Bar!"); + } + + @Test + public void exportsPdf() throws Exception { + HttpResponse<byte[]> response = report("pdf"); + + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.headers().firstValue("Content-Type")).hasValueSatisfying(type -> assertThat(type).startsWith("application/pdf")); + assertThat(response.body()).startsWith("%PDF".getBytes()); + } + + @Test + public void exportsHtml() throws Exception { + HttpResponse<byte[]> response = report("html"); + + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.headers().firstValue("Content-Type")).hasValueSatisfying(type -> assertThat(type).startsWith("text/html")); + assertThat(new String(response.body())).contains("Tomcat Report").contains("Hello Foo Bar!"); + } + + @Test + public void exportsXml() throws Exception { + HttpResponse<byte[]> response = report("xml"); + + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.headers().firstValue("Content-Type")).hasValueSatisfying(type -> assertThat(type).startsWith("text/xml")); + assertThat(new String(response.body())).contains("Tomcat Report").contains("Hello Foo Bar!"); + } + + @Test + public void exportsRtf() throws Exception { + HttpResponse<byte[]> response = report("rtf"); + + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.headers().firstValue("Content-Type")).hasValueSatisfying(type -> assertThat(type).startsWith("application/rtf")); + assertThat(new String(response.body())).startsWith("{\\rtf").contains("Hello Foo Bar!"); + } + + @Test + public void exportsXlsx() throws Exception { + HttpResponse<byte[]> response = report("xlsx"); + + assertThat(response.statusCode()).isEqualTo(200); + assertThat(response.headers().firstValue("Content-Type")).hasValueSatisfying(type -> assertThat(type).startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")); + assertThat(response.body()).startsWith("PK".getBytes()); + } + + private static HttpResponse<byte[]> report(String format) throws Exception { + HttpRequest request = HttpRequest.newBuilder(URI.create(baseUrl + "/report.action?format=" + format)).build(); + return HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofByteArray()); + } +} diff --git a/plugins/jasperreports7/src/test/java/org/apache/struts2/views/jasperreports7/tomcat/ReportAction.java b/plugins/jasperreports7/src/test/java/org/apache/struts2/views/jasperreports7/tomcat/ReportAction.java new file mode 100644 index 000000000..2543436f2 --- /dev/null +++ b/plugins/jasperreports7/src/test/java/org/apache/struts2/views/jasperreports7/tomcat/ReportAction.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.views.jasperreports7.tomcat; + +import org.apache.struts2.ActionSupport; +import org.apache.struts2.interceptor.parameter.StrutsParameter; + +import java.util.List; +import java.util.Map; + +public class ReportAction extends ActionSupport { + + private String format; + + public List<Map<String, String>> getPeople() { + return List.of(Map.of("firstName", "Foo", "lastName", "Bar")); + } + + public Map<String, Object> getReportParameters() { + return Map.of("title", "Tomcat"); + } + + public String getFormat() { + return format; + } + + @StrutsParameter + public void setFormat(String format) { + this.format = format; + } +} diff --git a/plugins/jasperreports7/src/test/resources/struts-tomcat.xml b/plugins/jasperreports7/src/test/resources/struts-tomcat.xml new file mode 100644 index 000000000..be465eada --- /dev/null +++ b/plugins/jasperreports7/src/test/resources/struts-tomcat.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +--> +<!DOCTYPE struts PUBLIC + "-//Apache Software Foundation//DTD Struts Configuration 6.0//EN" + "https://struts.apache.org/dtds/struts-6.0.dtd"> +<struts> + <package name="reports" extends="jasperreports7-default"> + <action name="report" class="org.apache.struts2.views.jasperreports7.tomcat.ReportAction"> + <result type="jasperReport7"> + <param name="location">/reports/simple.jasper</param> + <param name="dataSource">people</param> + <param name="reportParameters">reportParameters</param> + <param name="format">${format}</param> + </result> + </action> + </package> +</struts>
