Skip to content

Commit a291559

Browse files
authored
add more info on failures in FreemarkerAttachmentRenderer (via #921)
1 parent 3e3f173 commit a291559

8 files changed

Lines changed: 203 additions & 7 deletions

File tree

allure-attachments/src/main/java/io/qameta/allure/attachment/FreemarkerAttachmentRenderer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
import freemarker.template.Configuration;
1919
import freemarker.template.Template;
20+
import freemarker.template.TemplateExceptionHandler;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
2023

2124
import java.io.StringWriter;
2225
import java.io.Writer;
@@ -27,6 +30,8 @@
2730
*/
2831
public class FreemarkerAttachmentRenderer implements AttachmentRenderer<AttachmentData> {
2932

33+
private static final Logger LOGGER = LoggerFactory.getLogger(FreemarkerAttachmentRenderer.class);
34+
3035
private final Configuration configuration;
3136

3237
private final String templateName;
@@ -36,6 +41,7 @@ public FreemarkerAttachmentRenderer(final String templateName) {
3641
this.configuration = new Configuration(Configuration.VERSION_2_3_23);
3742
this.configuration.setLocalizedLookup(false);
3843
this.configuration.setTemplateUpdateDelayMilliseconds(0);
44+
this.configuration.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
3945
this.configuration.setClassLoaderForTemplateLoading(getClass().getClassLoader(), "tpl");
4046
}
4147

@@ -46,6 +52,7 @@ public DefaultAttachmentContent render(final AttachmentData data) {
4652
template.process(Collections.singletonMap("data", data), writer);
4753
return new DefaultAttachmentContent(writer.toString(), "text/html", ".html");
4854
} catch (Exception e) {
55+
LOGGER.debug(data.toString());
4956
throw new AttachmentRenderException("Could't render http attachment file", e);
5057
}
5158
}

allure-attachments/src/main/java/io/qameta/allure/attachment/http/HttpRequestAttachment.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.qameta.allure.attachment.http;
1717

1818
import io.qameta.allure.attachment.AttachmentData;
19+
import io.qameta.allure.util.ObjectUtils;
1920

2021
import java.util.HashMap;
2122
import java.util.Map;
@@ -81,6 +82,17 @@ public String getName() {
8182
return name;
8283
}
8384

85+
@Override
86+
public String toString() {
87+
return "HttpRequestAttachment("
88+
+ "\n\tname=" + this.name
89+
+ ",\n\turl=" + this.url
90+
+ ",\n\tbody=" + this.body
91+
+ ",\n\theaders=" + ObjectUtils.mapToString(this.headers)
92+
+ ",\n\tcookies=" + ObjectUtils.mapToString(this.cookies)
93+
+ "\n)";
94+
}
95+
8496
/**
8597
* Builder for HttpRequestAttachment.
8698
*/

allure-attachments/src/main/java/io/qameta/allure/attachment/http/HttpResponseAttachment.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.qameta.allure.attachment.http;
1717

1818
import io.qameta.allure.attachment.AttachmentData;
19+
import io.qameta.allure.util.ObjectUtils;
1920

2021
import java.util.HashMap;
2122
import java.util.Map;
@@ -74,6 +75,18 @@ public Map<String, String> getCookies() {
7475
return cookies;
7576
}
7677

78+
@Override
79+
public String toString() {
80+
return "HttpResponseAttachment("
81+
+ "\n\tname=" + this.name
82+
+ ",\n\turl=" + this.url
83+
+ ",\n\tbody=" + this.body
84+
+ ",\n\tresponseCode=" + this.responseCode
85+
+ ",\n\theaders=" + ObjectUtils.mapToString(this.headers)
86+
+ ",\n\tcookies=" + ObjectUtils.mapToString(this.cookies)
87+
+ "\n)";
88+
}
89+
7790
/**
7891
* Builder for HttpRequestAttachment.
7992
*/
@@ -146,6 +159,7 @@ public Builder setBody(final String body) {
146159

147160
/**
148161
* Use setter method instead.
162+
*
149163
* @deprecated scheduled for removal in 3.0 release
150164
*/
151165
@Deprecated
@@ -155,6 +169,7 @@ public Builder withUrl(final String url) {
155169

156170
/**
157171
* Use setter method instead.
172+
*
158173
* @deprecated scheduled for removal in 3.0 release
159174
*/
160175
@Deprecated
@@ -164,6 +179,7 @@ public Builder withResponseCode(final int responseCode) {
164179

165180
/**
166181
* Use setter method instead.
182+
*
167183
* @deprecated scheduled for removal in 3.0 release
168184
*/
169185
@Deprecated
@@ -173,6 +189,7 @@ public Builder withHeader(final String name, final String value) {
173189

174190
/**
175191
* Use setter method instead.
192+
*
176193
* @deprecated scheduled for removal in 3.0 release
177194
*/
178195
@Deprecated
@@ -182,6 +199,7 @@ public Builder withHeaders(final Map<String, String> headers) {
182199

183200
/**
184201
* Use setter method instead.
202+
*
185203
* @deprecated scheduled for removal in 3.0 release
186204
*/
187205
@Deprecated
@@ -191,6 +209,7 @@ public Builder withCookie(final String name, final String value) {
191209

192210
/**
193211
* Use setter method instead.
212+
*
194213
* @deprecated scheduled for removal in 3.0 release
195214
*/
196215
@Deprecated
@@ -200,6 +219,7 @@ public Builder withCookies(final Map<String, String> cookies) {
200219

201220
/**
202221
* Use setter method instead.
222+
*
203223
* @deprecated scheduled for removal in 3.0 release
204224
*/
205225
@Deprecated

allure-attachments/src/test/java/io/qameta/allure/attachment/FreemarkerAttachmentRendererTest.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,26 @@
1616
package io.qameta.allure.attachment;
1717

1818
import io.qameta.allure.attachment.http.HttpRequestAttachment;
19+
import io.qameta.allure.attachment.http.HttpResponseAttachment;
1920
import io.qameta.allure.test.AllureFeatures;
2021
import org.junit.jupiter.api.Test;
2122

2223
import static io.qameta.allure.attachment.testdata.TestData.randomHttpRequestAttachment;
24+
import static io.qameta.allure.attachment.testdata.TestData.randomHttpResponseAttachment;
2325
import static org.assertj.core.api.Assertions.assertThat;
2426

2527
/**
2628
* @author charlie (Dmitry Baev).
2729
*/
2830
class FreemarkerAttachmentRendererTest {
2931

32+
private static final String CONTENT = "content";
33+
private static final String CONTENT_TYPE = "contentType";
34+
private static final String TEXT_HTML = "text/html";
35+
private static final String FILE_EXTENSION = "fileExtension";
36+
private static final String HTML = ".html";
37+
38+
3039
@AllureFeatures.Attachments
3140
@Test
3241
void shouldRenderRequestAttachment() {
@@ -35,21 +44,21 @@ void shouldRenderRequestAttachment() {
3544
.render(data);
3645

3746
assertThat(content)
38-
.hasFieldOrPropertyWithValue("contentType", "text/html")
39-
.hasFieldOrPropertyWithValue("fileExtension", ".html")
40-
.hasFieldOrProperty("content");
47+
.hasFieldOrPropertyWithValue(CONTENT_TYPE, TEXT_HTML)
48+
.hasFieldOrPropertyWithValue(FILE_EXTENSION, HTML)
49+
.hasFieldOrProperty(CONTENT);
4150
}
4251

4352
@AllureFeatures.Attachments
4453
@Test
4554
void shouldRenderResponseAttachment() {
46-
final HttpRequestAttachment data = randomHttpRequestAttachment();
55+
final HttpResponseAttachment data = randomHttpResponseAttachment();
4756
final DefaultAttachmentContent content = new FreemarkerAttachmentRenderer("http-response.ftl")
4857
.render(data);
4958

5059
assertThat(content)
51-
.hasFieldOrPropertyWithValue("contentType", "text/html")
52-
.hasFieldOrPropertyWithValue("fileExtension", ".html")
53-
.hasFieldOrProperty("content");
60+
.hasFieldOrPropertyWithValue(CONTENT_TYPE, TEXT_HTML)
61+
.hasFieldOrPropertyWithValue(FILE_EXTENSION, HTML)
62+
.hasFieldOrProperty(CONTENT);
5463
}
5564
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2019 Qameta Software OÜ
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.qameta.allure.attachment;
17+
18+
import io.qameta.allure.attachment.http.HttpRequestAttachment;
19+
import io.qameta.allure.test.AllureFeatures;
20+
import org.junit.jupiter.api.AfterEach;
21+
import org.junit.jupiter.api.BeforeEach;
22+
import org.junit.jupiter.api.Test;
23+
24+
import java.io.ByteArrayOutputStream;
25+
import java.io.PrintStream;
26+
import java.io.UnsupportedEncodingException;
27+
import java.nio.charset.StandardCharsets;
28+
29+
import static io.qameta.allure.attachment.testdata.TestData.negativeHttpRequestAttachment;
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.junit.jupiter.api.Assertions.assertThrows;
32+
33+
/**
34+
* @author a-simeshin (Simeshin Artem).
35+
*/
36+
class NegativeFreemarkerAttachmentRendererTest {
37+
38+
private static final String TEMPLATE_FOR_EXCEPTION = "body-npe-non-safe-attachment.ftl";
39+
40+
private PrintStream realSysOut;
41+
private ByteArrayOutputStream sysOutBuffer;
42+
43+
@BeforeEach
44+
void setUpSysOut() throws UnsupportedEncodingException {
45+
realSysOut = System.err;
46+
sysOutBuffer = new ByteArrayOutputStream();
47+
System.setErr(new PrintStream(sysOutBuffer, false, StandardCharsets.UTF_8.toString()));
48+
}
49+
50+
@AfterEach
51+
void rollBackSysOut() {
52+
System.setErr(realSysOut);
53+
}
54+
55+
@AllureFeatures.Attachments
56+
@Test
57+
void shouldThrowExceptionalSituationsForFreeMarketRendererWithIncorrectAttachmentData() {
58+
assertThrows(AttachmentRenderException.class, () -> {
59+
final HttpRequestAttachment data = negativeHttpRequestAttachment();
60+
new FreemarkerAttachmentRenderer(TEMPLATE_FOR_EXCEPTION).render(data);
61+
});
62+
}
63+
64+
@AllureFeatures.Attachments
65+
@Test
66+
void shouldExplainExceptionalSituationsForFreeMarketRenderer() throws UnsupportedEncodingException {
67+
try {
68+
final HttpRequestAttachment data = negativeHttpRequestAttachment();
69+
new FreemarkerAttachmentRenderer(TEMPLATE_FOR_EXCEPTION).render(data);
70+
} catch (Exception ignored) {
71+
// for test purposes
72+
}
73+
assertThat(sysOutBuffer.toString(StandardCharsets.UTF_8.toString()))
74+
.contains("SEVERE: Error executing FreeMarker template")
75+
.contains("FreeMarker template error:")
76+
.contains("The following has evaluated to null or missing:")
77+
.contains("==> data.body")
78+
.contains("[in template \"body-npe-non-safe-attachment.ftl\" at line 8, column 11]")
79+
.contains("\t- Failed at: ${data.body.size}")
80+
.contains("io.qameta.allure.attachment.FreemarkerAttachmentRenderer - HttpRequestAttachment")
81+
.contains("\tname=null,")
82+
.contains("\turl=null,")
83+
.contains("\tbody=null,")
84+
.contains("\theaders={},")
85+
.contains("\tcookies={}");
86+
}
87+
}

allure-attachments/src/test/java/io/qameta/allure/attachment/testdata/TestData.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,17 @@ public static Map<String, String> randomMap() {
7272
map.put(randomString(), null);
7373
return map;
7474
}
75+
76+
public static HttpRequestAttachment negativeHttpRequestAttachment() {
77+
return new HttpRequestAttachment(
78+
null,
79+
null,
80+
null,
81+
null,
82+
null,
83+
null,
84+
null
85+
);
86+
}
87+
7588
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<#ftl output_format="HTML">
2+
<#-- @ftlvariable name="data" type="io.qameta.allure.attachment.http.HttpRequestAttachment" -->
3+
<div><#if data.method??>${data.method}<#else>GET</#if> to <#if data.url??>${data.url}<#else>Unknown</#if></div>
4+
5+
<h4>Body</h4>
6+
<div>
7+
<pre class="preformatted-text">
8+
<#t>${data.body.size}
9+
</pre>
10+
</div>
11+
12+
<#if (data.headers)?has_content>
13+
<h4>Headers</h4>
14+
<div>
15+
<#list data.headers as name, value>
16+
<div>${name}: ${value!"null"}</div>
17+
</#list>
18+
</div>
19+
</#if>
20+
21+
22+
<#if (data.cookies)?has_content>
23+
<h4>Cookies</h4>
24+
<div>
25+
<#list data.cookies as name, value>
26+
<div>${name}: ${value!"null"}</div>
27+
</#list>
28+
</div>
29+
</#if>
30+
31+
<#if data.curl??>
32+
<h4>Curl</h4>
33+
<div>
34+
${data.curl}
35+
</div>
36+
</#if>

allure-java-commons/src/main/java/io/qameta/allure/util/ObjectUtils.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import org.slf4j.LoggerFactory;
2020

2121
import java.util.Arrays;
22+
import java.util.Map;
2223
import java.util.Objects;
24+
import java.util.stream.Collectors;
2325

2426
/**
2527
* @author charlie (Dmitry Baev).
@@ -76,4 +78,14 @@ public static String toString(final Object object) {
7678
return "<NPE>";
7779
}
7880
}
81+
82+
public static String mapToString(final Map<String, String> map) {
83+
if (map == null || map.isEmpty()) {
84+
return "{}";
85+
}
86+
return map.keySet()
87+
.stream()
88+
.map(key -> key + "=" + map.get(key))
89+
.collect(Collectors.joining(",", "{", "}"));
90+
}
7991
}

0 commit comments

Comments
 (0)