Skip to content

Commit 0621a8e

Browse files
committed
Fix concurrency issues in FreeMarkerMacroTests
Prior to this commit, tests in these two classes intermittently failed with errors similar to the following, due to concurrent modification of shared files. expected: "<input type="text" id="name" name="name" value="Darren" >" but was: "<input type="text" id="name" name="name" value="Darren" > "hidden"/>" This commit fixes this by creating a new temporary folder for each test method invocation.
1 parent 7ac646b commit 0621a8e

File tree

2 files changed

+72
-54
lines changed

2 files changed

+72
-54
lines changed

spring-webflux/src/test/java/org/springframework/web/reactive/result/view/freemarker/FreeMarkerMacroTests.java

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,9 +16,10 @@
1616

1717
package org.springframework.web.reactive.result.view.freemarker;
1818

19-
import java.io.FileWriter;
2019
import java.io.IOException;
2120
import java.io.InputStreamReader;
21+
import java.nio.file.Files;
22+
import java.nio.file.Path;
2223
import java.util.Arrays;
2324
import java.util.HashMap;
2425
import java.util.List;
@@ -32,7 +33,6 @@
3233
import org.springframework.beans.testfixture.beans.TestBean;
3334
import org.springframework.context.support.GenericApplicationContext;
3435
import org.springframework.core.io.ClassPathResource;
35-
import org.springframework.core.io.FileSystemResource;
3636
import org.springframework.http.MediaType;
3737
import org.springframework.ui.ExtendedModelMap;
3838
import org.springframework.ui.ModelMap;
@@ -45,6 +45,7 @@
4545
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
4646
import org.springframework.web.testfixture.server.MockServerWebExchange;
4747

48+
import static java.nio.charset.StandardCharsets.UTF_8;
4849
import static java.util.Collections.singletonMap;
4950
import static java.util.stream.Collectors.toList;
5051
import static org.assertj.core.api.Assertions.assertThat;
@@ -66,12 +67,17 @@ public class FreeMarkerMacroTests {
6667

6768
private Configuration freeMarkerConfig;
6869

70+
private Path templateLoaderPath;
71+
72+
6973
@BeforeEach
7074
public void setUp() throws Exception {
75+
this.templateLoaderPath = Files.createTempDirectory("webflux-").toAbsolutePath();
76+
7177
this.applicationContext.refresh();
7278

7379
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
74-
configurer.setTemplateLoaderPaths("classpath:/", "file://" + System.getProperty("java.io.tmpdir"));
80+
configurer.setTemplateLoaderPaths("classpath:/", "file://" + this.templateLoaderPath);
7581
this.freeMarkerConfig = configurer.createConfiguration();
7682
}
7783

@@ -333,23 +339,26 @@ private List<String> getMacroOutput(String name) throws Exception {
333339
return getOutput();
334340
}
335341

336-
private String fetchMacro(String name) throws Exception {
337-
ClassPathResource resource = new ClassPathResource(TEMPLATE_FILE, getClass());
338-
assertThat(resource.exists()).isTrue();
339-
String all = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
340-
all = all.replace("\r\n", "\n");
341-
String[] macros = StringUtils.delimitedListToStringArray(all, "\n\n");
342-
for (String macro : macros) {
342+
private static String fetchMacro(String name) throws Exception {
343+
for (String macro : loadMacros()) {
343344
if (macro.startsWith(name)) {
344345
return macro.substring(macro.indexOf("\n")).trim();
345346
}
346347
}
347348
return null;
348349
}
349350

351+
private static String[] loadMacros() throws IOException {
352+
ClassPathResource resource = new ClassPathResource(TEMPLATE_FILE, FreeMarkerMacroTests.class);
353+
assertThat(resource.exists()).isTrue();
354+
String all = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
355+
all = all.replace("\r\n", "\n");
356+
return StringUtils.delimitedListToStringArray(all, "\n\n");
357+
}
358+
350359
private void storeTemplateInTempDir(String macro) throws IOException {
351-
FileSystemResource resource = new FileSystemResource(System.getProperty("java.io.tmpdir") + "/tmp.ftl");
352-
FileCopyUtils.copy("<#import \"spring.ftl\" as spring />\n" + macro, new FileWriter(resource.getPath()));
360+
Files.write(this.templateLoaderPath.resolve("tmp.ftl"),
361+
("<#import \"spring.ftl\" as spring />\n" + macro).getBytes(UTF_8));
353362
}
354363

355364
private List<String> getOutput() {

spring-webmvc/src/test/java/org/springframework/web/servlet/view/freemarker/FreeMarkerMacroTests.java

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,12 +16,13 @@
1616

1717
package org.springframework.web.servlet.view.freemarker;
1818

19-
import java.io.FileWriter;
19+
import java.io.IOException;
2020
import java.io.InputStreamReader;
21+
import java.nio.file.Files;
22+
import java.nio.file.Path;
2123
import java.util.HashMap;
2224
import java.util.Map;
2325

24-
import javax.servlet.ServletContext;
2526
import javax.servlet.ServletException;
2627
import javax.servlet.http.HttpServletResponse;
2728

@@ -34,7 +35,6 @@
3435

3536
import org.springframework.beans.testfixture.beans.TestBean;
3637
import org.springframework.core.io.ClassPathResource;
37-
import org.springframework.core.io.FileSystemResource;
3838
import org.springframework.util.FileCopyUtils;
3939
import org.springframework.util.StringUtils;
4040
import org.springframework.web.context.support.StaticWebApplicationContext;
@@ -49,6 +49,7 @@
4949
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
5050
import org.springframework.web.testfixture.servlet.MockServletContext;
5151

52+
import static java.nio.charset.StandardCharsets.UTF_8;
5253
import static org.assertj.core.api.Assertions.assertThat;
5354

5455
/**
@@ -61,35 +62,34 @@ public class FreeMarkerMacroTests {
6162

6263
private static final String TEMPLATE_FILE = "test.ftl";
6364

64-
private StaticWebApplicationContext wac;
65+
private final StaticWebApplicationContext wac = new StaticWebApplicationContext();
6566

66-
private MockHttpServletRequest request;
67+
private final MockServletContext servletContext = new MockServletContext();
6768

68-
private MockHttpServletResponse response;
69+
private final MockHttpServletRequest request = new MockHttpServletRequest();
6970

70-
private FreeMarkerConfigurer fc;
71+
private final MockHttpServletResponse response = new MockHttpServletResponse();
72+
73+
private final FreeMarkerConfigurer fc = new FreeMarkerConfigurer();
74+
75+
private Path templateLoaderPath;
7176

7277

7378
@BeforeEach
7479
public void setUp() throws Exception {
75-
ServletContext sc = new MockServletContext();
76-
wac = new StaticWebApplicationContext();
77-
wac.setServletContext(sc);
78-
79-
// final Template expectedTemplate = new Template();
80-
fc = new FreeMarkerConfigurer();
81-
fc.setTemplateLoaderPaths("classpath:/", "file://" + System.getProperty("java.io.tmpdir"));
82-
fc.setServletContext(sc);
80+
this.templateLoaderPath = Files.createTempDirectory("servlet-").toAbsolutePath();
81+
82+
fc.setTemplateLoaderPaths("classpath:/", "file://" + this.templateLoaderPath);
83+
fc.setServletContext(servletContext);
8384
fc.afterPropertiesSet();
8485

86+
wac.setServletContext(servletContext);
8587
wac.getDefaultListableBeanFactory().registerSingleton("freeMarkerConfigurer", fc);
8688
wac.refresh();
8789

88-
request = new MockHttpServletRequest();
8990
request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
9091
request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver());
9192
request.setAttribute(DispatcherServlet.THEME_RESOLVER_ATTRIBUTE, new FixedThemeResolver());
92-
response = new MockHttpServletResponse();
9393
}
9494

9595

@@ -203,12 +203,12 @@ public void testUrlParams() throws Exception {
203203

204204
@Test
205205
public void testForm1() throws Exception {
206-
assertThat(getMacroOutput("FORM1")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" >");
206+
assertThat(getMacroOutput("FORM1")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" >");
207207
}
208208

209209
@Test
210210
public void testForm2() throws Exception {
211-
assertThat(getMacroOutput("FORM2")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" class=\"myCssClass\" >");
211+
assertThat(getMacroOutput("FORM2")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" class=\"myCssClass\" >");
212212
}
213213

214214
@Test
@@ -225,27 +225,27 @@ public void testForm4() throws Exception {
225225

226226
@Test
227227
public void testForm9() throws Exception {
228-
assertThat(getMacroOutput("FORM9")).isEqualTo("<input type=\"password\" id=\"name\" name=\"name\" value=\"\" >");
228+
assertThat(getMacroOutput("FORM9")).isEqualTo("<input type=\"password\" id=\"name\" name=\"name\" value=\"\" >");
229229
}
230230

231231
@Test
232232
public void testForm10() throws Exception {
233-
assertThat(getMacroOutput("FORM10")).isEqualTo("<input type=\"hidden\" id=\"name\" name=\"name\" value=\"Darren\" >");
233+
assertThat(getMacroOutput("FORM10")).isEqualTo("<input type=\"hidden\" id=\"name\" name=\"name\" value=\"Darren\" >");
234234
}
235235

236236
@Test
237237
public void testForm11() throws Exception {
238-
assertThat(getMacroOutput("FORM11")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" >");
238+
assertThat(getMacroOutput("FORM11")).isEqualTo("<input type=\"text\" id=\"name\" name=\"name\" value=\"Darren\" >");
239239
}
240240

241241
@Test
242242
public void testForm12() throws Exception {
243-
assertThat(getMacroOutput("FORM12")).isEqualTo("<input type=\"hidden\" id=\"name\" name=\"name\" value=\"Darren\" >");
243+
assertThat(getMacroOutput("FORM12")).isEqualTo("<input type=\"hidden\" id=\"name\" name=\"name\" value=\"Darren\" >");
244244
}
245245

246246
@Test
247247
public void testForm13() throws Exception {
248-
assertThat(getMacroOutput("FORM13")).isEqualTo("<input type=\"password\" id=\"name\" name=\"name\" value=\"\" >");
248+
assertThat(getMacroOutput("FORM13")).isEqualTo("<input type=\"password\" id=\"name\" name=\"name\" value=\"\" >");
249249
}
250250

251251
@Test
@@ -266,7 +266,7 @@ public void testForm16() throws Exception {
266266

267267
@Test
268268
public void testForm17() throws Exception {
269-
assertThat(getMacroOutput("FORM17")).isEqualTo("<input type=\"text\" id=\"spouses0.name\" name=\"spouses[0].name\" value=\"Fred\" >");
269+
assertThat(getMacroOutput("FORM17")).isEqualTo("<input type=\"text\" id=\"spouses0.name\" name=\"spouses[0].name\" value=\"Fred\" >");
270270
}
271271

272272
@Test
@@ -282,9 +282,7 @@ public void testForm18() throws Exception {
282282
private String getMacroOutput(String name) throws Exception {
283283
String macro = fetchMacro(name);
284284
assertThat(macro).isNotNull();
285-
286-
FileSystemResource resource = new FileSystemResource(System.getProperty("java.io.tmpdir") + "/tmp.ftl");
287-
FileCopyUtils.copy("<#import \"spring.ftl\" as spring />\n" + macro, new FileWriter(resource.getPath()));
285+
storeTemplateInTempDir(macro);
288286

289287
DummyMacroRequestContext rc = new DummyMacroRequestContext(request);
290288
Map<String, String> msgMap = new HashMap<>();
@@ -324,28 +322,39 @@ private String getMacroOutput(String name) throws Exception {
324322
view.setUrl("tmp.ftl");
325323
view.setExposeSpringMacroHelpers(false);
326324
view.setConfiguration(config);
327-
view.setServletContext(new MockServletContext());
325+
view.setServletContext(servletContext);
328326

329327
view.render(model, request, response);
330328

331-
// tokenize output and ignore whitespace
332-
String output = response.getContentAsString();
333-
output = output.replace("\r\n", "\n");
334-
return output.trim();
329+
return getOutput();
335330
}
336331

337-
private String fetchMacro(String name) throws Exception {
338-
ClassPathResource resource = new ClassPathResource("test.ftl", getClass());
339-
assertThat(resource.exists()).isTrue();
340-
String all = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
341-
all = all.replace("\r\n", "\n");
342-
String[] macros = StringUtils.delimitedListToStringArray(all, "\n\n");
343-
for (String macro : macros) {
332+
private static String fetchMacro(String name) throws Exception {
333+
for (String macro : loadMacros()) {
344334
if (macro.startsWith(name)) {
345335
return macro.substring(macro.indexOf("\n")).trim();
346336
}
347337
}
348338
return null;
349339
}
350340

341+
private static String[] loadMacros() throws IOException {
342+
ClassPathResource resource = new ClassPathResource("test.ftl", FreeMarkerMacroTests.class);
343+
assertThat(resource.exists()).isTrue();
344+
String all = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
345+
all = all.replace("\r\n", "\n");
346+
return StringUtils.delimitedListToStringArray(all, "\n\n");
347+
}
348+
349+
private void storeTemplateInTempDir(String macro) throws IOException {
350+
Files.write(this.templateLoaderPath.resolve("tmp.ftl"),
351+
("<#import \"spring.ftl\" as spring />\n" + macro).getBytes(UTF_8));
352+
}
353+
354+
private String getOutput() throws IOException {
355+
String output = response.getContentAsString();
356+
output = output.replace("\r\n", "\n").replaceAll(" +"," ");
357+
return output.trim();
358+
}
359+
351360
}

0 commit comments

Comments
 (0)