Skip to content

Commit 7d96ad1

Browse files
Rob Winchrstoyanchev
authored andcommitted
MockMvc HtmlUnit support shares CookieManager
Previously MockMvc builders failed to share the WebConnection used for managing cookies in the MockMvcWebConnection. This meant that the various CookieManagers would have different states. This commit ensures that the WebConnection is set on the MockMvcWebConnection. Fixes SPR-14066
1 parent 8246fe4 commit 7d96ad1

File tree

9 files changed

+197
-19
lines changed

9 files changed

+197
-19
lines changed

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebClientBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public static MockMvcWebClientBuilder webAppContextSetup(WebApplicationContext c
106106
*/
107107
public MockMvcWebClientBuilder withDelegate(WebClient webClient) {
108108
Assert.notNull(webClient, "WebClient must not be null");
109-
webClient.setWebConnection(createConnection(webClient.getWebConnection()));
109+
webClient.setWebConnection(createConnection(webClient));
110110
this.webClient = webClient;
111111
return this;
112112
}

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnection.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@ public final class MockMvcWebConnection implements WebConnection {
6363

6464
private WebClient webClient;
6565

66-
6766
/**
6867
* Create a new instance that assumes the context path of the application
6968
* is {@code ""} (i.e., the root context).
7069
* <p>For example, the URL {@code http://localhost/test/this} would use
7170
* {@code ""} as the context path.
7271
* @param mockMvc the {@code MockMvc} instance to use; never {@code null}
72+
* @param webClient the {@link WebClient} to use. never {@code null}
7373
*/
74-
public MockMvcWebConnection(MockMvc mockMvc) {
75-
this(mockMvc, "");
74+
public MockMvcWebConnection(MockMvc mockMvc, WebClient webClient) {
75+
this(mockMvc, webClient, "");
7676
}
7777

7878
/**
@@ -83,17 +83,47 @@ public MockMvcWebConnection(MockMvc mockMvc) {
8383
* which states that it can be an empty string and otherwise must start
8484
* with a "/" character and not end with a "/" character.
8585
* @param mockMvc the {@code MockMvc} instance to use; never {@code null}
86+
* @param webClient the {@link WebClient} to use. never {@code null}
8687
* @param contextPath the contextPath to use
8788
*/
88-
public MockMvcWebConnection(MockMvc mockMvc, String contextPath) {
89+
public MockMvcWebConnection(MockMvc mockMvc, WebClient webClient, String contextPath) {
8990
Assert.notNull(mockMvc, "MockMvc must not be null");
91+
Assert.notNull(webClient, "WebClient must not be null");
9092
validateContextPath(contextPath);
9193

92-
this.webClient = new WebClient();
94+
this.webClient = webClient;
9395
this.mockMvc = mockMvc;
9496
this.contextPath = contextPath;
9597
}
9698

99+
/**
100+
* Create a new instance that assumes the context path of the application
101+
* is {@code ""} (i.e., the root context).
102+
* <p>For example, the URL {@code http://localhost/test/this} would use
103+
* {@code ""} as the context path.
104+
* @param mockMvc the {@code MockMvc} instance to use; never {@code null}
105+
* @deprecated Use {@link #MockMvcWebConnection(MockMvc, WebClient)}
106+
*/
107+
@Deprecated
108+
public MockMvcWebConnection(MockMvc mockMvc) {
109+
this(mockMvc, "");
110+
}
111+
112+
/**
113+
* Create a new instance with the specified context path.
114+
* <p>The path may be {@code null} in which case the first path segment
115+
* of the URL is turned into the contextPath. Otherwise it must conform
116+
* to {@link javax.servlet.http.HttpServletRequest#getContextPath()}
117+
* which states that it can be an empty string and otherwise must start
118+
* with a "/" character and not end with a "/" character.
119+
* @param mockMvc the {@code MockMvc} instance to use; never {@code null}
120+
* @param contextPath the contextPath to use
121+
* @deprecated use {@link #MockMvcWebConnection(MockMvc, WebClient, String)}
122+
*/
123+
@Deprecated
124+
public MockMvcWebConnection(MockMvc mockMvc, String contextPath) {
125+
this(mockMvc, new WebClient(), contextPath);
126+
}
97127

98128
public void setWebClient(WebClient webClient) {
99129
Assert.notNull(webClient, "WebClient must not be null");

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionBuilderSupport.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.ArrayList;
2020
import java.util.List;
2121

22+
import com.gargoylesoftware.htmlunit.WebClient;
2223
import com.gargoylesoftware.htmlunit.WebConnection;
2324

2425
import org.springframework.test.web.servlet.MockMvc;
@@ -145,10 +146,46 @@ public T useMockMvcForHosts(String... hosts) {
145146
* @see #alwaysUseMockMvc()
146147
* @see #useMockMvc(WebRequestMatcher...)
147148
* @see #useMockMvcForHosts(String...)
149+
* @deprecated Use {@link #createConnection(WebClient)} instead
148150
*/
151+
@Deprecated
149152
protected final WebConnection createConnection(WebConnection defaultConnection) {
150153
Assert.notNull(defaultConnection, "Default WebConnection must not be null");
151-
MockMvcWebConnection mockMvcWebConnection = new MockMvcWebConnection(this.mockMvc, this.contextPath);
154+
return createConnection(new WebClient(), defaultConnection);
155+
}
156+
157+
/**
158+
* Create a new {@link WebConnection} that will use a {@link MockMvc}
159+
* instance if one of the specified {@link WebRequestMatcher} instances
160+
* matches.
161+
* @param webClient the WebClient to use if none of
162+
* the specified {@code WebRequestMatcher} instances matches; never {@code null}
163+
* @return a new {@code WebConnection} that will use a {@code MockMvc}
164+
* instance if one of the specified {@code WebRequestMatcher} matches
165+
* @see #alwaysUseMockMvc()
166+
* @see #useMockMvc(WebRequestMatcher...)
167+
* @see #useMockMvcForHosts(String...)
168+
*/
169+
protected final WebConnection createConnection(WebClient webClient) {
170+
Assert.notNull(webClient, "WebClient must not be null");
171+
return createConnection(webClient, webClient.getWebConnection());
172+
}
173+
174+
/**
175+
* Create a new {@link WebConnection} that will use a {@link MockMvc}
176+
* instance if one of the specified {@link WebRequestMatcher} instances
177+
* matches.
178+
* @param webClient the WebClient to use if none of
179+
* the specified {@code WebRequestMatcher} instances matches; never {@code null}
180+
* @param defaultConnection the WebConnection to use
181+
* @return a new {@code WebConnection} that will use a {@code MockMvc}
182+
* instance if one of the specified {@code WebRequestMatcher} matches
183+
* @see #alwaysUseMockMvc()
184+
* @see #useMockMvc(WebRequestMatcher...)
185+
* @see #useMockMvcForHosts(String...)
186+
*/
187+
private WebConnection createConnection(WebClient webClient, WebConnection defaultConnection) {
188+
MockMvcWebConnection mockMvcWebConnection = new MockMvcWebConnection(this.mockMvc, webClient, this.contextPath);
152189

153190
if (this.alwaysUseMockMvc) {
154191
return mockMvcWebConnection;
@@ -162,5 +199,4 @@ protected final WebConnection createConnection(WebConnection defaultConnection)
162199

163200
return new DelegatingWebConnection(defaultConnection, delegates);
164201
}
165-
166202
}

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/webdriver/MockMvcHtmlUnitDriverBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public MockMvcHtmlUnitDriverBuilder javascriptEnabled(boolean javascriptEnabled)
129129
public MockMvcHtmlUnitDriverBuilder withDelegate(WebConnectionHtmlUnitDriver driver) {
130130
Assert.notNull(driver, "HtmlUnitDriver must not be null");
131131
driver.setJavascriptEnabled(this.javascriptEnabled);
132-
driver.setWebConnection(createConnection(driver.getWebConnection()));
132+
driver.setWebConnection(createConnection(driver.getWebClient()));
133133
this.driver = driver;
134134
return this;
135135
}

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/webdriver/WebConnectionHtmlUnitDriver.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ public class WebConnectionHtmlUnitDriver extends HtmlUnitDriver {
4141

4242
private WebClient webClient;
4343

44-
4544
public WebConnectionHtmlUnitDriver(BrowserVersion browserVersion) {
4645
super(browserVersion);
4746
}
@@ -107,4 +106,11 @@ public void setWebConnection(WebConnection webConnection) {
107106
this.webClient.setWebConnection(webConnection);
108107
}
109108

109+
/**
110+
* Gets the current {@link WebClient}
111+
* @return the current {@link WebClient}
112+
*/
113+
public WebClient getWebClient() {
114+
return this.webClient;
115+
}
110116
}

spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/MockMvcConnectionBuilderSupportTests.java

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.web.context.WebApplicationContext;
3737
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
3838

39+
import com.gargoylesoftware.htmlunit.WebClient;
3940
import com.gargoylesoftware.htmlunit.WebConnection;
4041
import com.gargoylesoftware.htmlunit.WebRequest;
4142
import com.gargoylesoftware.htmlunit.WebResponse;
@@ -45,6 +46,7 @@
4546
import static org.hamcrest.Matchers.notNullValue;
4647
import static org.junit.Assert.assertThat;
4748
import static org.mockito.Mockito.mock;
49+
import static org.mockito.Mockito.when;
4850

4951
/**
5052
* Integration tests for {@link MockMvcWebConnectionBuilderSupport}.
@@ -55,10 +57,12 @@
5557
@RunWith(SpringJUnit4ClassRunner.class)
5658
@ContextConfiguration
5759
@WebAppConfiguration
58-
@SuppressWarnings("rawtypes")
60+
@SuppressWarnings({"rawtypes","deprecation"})
5961
public class MockMvcConnectionBuilderSupportTests {
6062

61-
private final WebConnection delegateConnection = mock(WebConnection.class);
63+
private WebConnection delegateConnection;
64+
65+
private WebClient webClient;
6266

6367
@Autowired
6468
private WebApplicationContext wac;
@@ -69,10 +73,16 @@ public class MockMvcConnectionBuilderSupportTests {
6973

7074
@Before
7175
public void setup() {
76+
delegateConnection = mock(WebConnection.class);
77+
78+
webClient = mock(WebClient.class);
79+
when(webClient.getWebConnection()).thenReturn(delegateConnection);
80+
81+
7282
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
7383

7484
connection = new MockMvcWebConnectionBuilderSupport(mockMvc){}
75-
.createConnection(delegateConnection);
85+
.createConnection(webClient);
7686
}
7787

7888
@Test(expected = IllegalArgumentException.class)
@@ -86,10 +96,61 @@ public void constructorContextNull() {
8696
}
8797

8898
@Test
89-
public void context() throws Exception {
99+
public void contextDeprecated() throws Exception {
100+
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
101+
.createConnection(webClient);
102+
103+
assertMvcProcessed("http://localhost/");
104+
assertDelegateProcessed("http://example.com/");
105+
}
106+
107+
@Test
108+
public void mockMvcDeprecated() throws Exception {
109+
assertMvcProcessed("http://localhost/");
110+
assertDelegateProcessed("http://example.com/");
111+
}
112+
113+
@Test
114+
public void mockMvcExampleDotComDeprecated() throws Exception {
115+
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
116+
.useMockMvcForHosts("example.com")
117+
.createConnection(delegateConnection);
118+
119+
assertMvcProcessed("http://localhost/");
120+
assertMvcProcessed("http://example.com/");
121+
assertDelegateProcessed("http://other.com/");
122+
}
123+
124+
@Test
125+
public void mockMvcAlwaysUseMockMvcDeprecated() throws Exception {
126+
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
127+
.alwaysUseMockMvc()
128+
.createConnection(delegateConnection);
129+
130+
assertMvcProcessed("http://other.com/");
131+
}
132+
133+
@Test
134+
public void defaultContextPathEmptyDeprecated() throws Exception {
90135
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
91136
.createConnection(delegateConnection);
92137

138+
assertThat(getWebResponse("http://localhost/abc").getContentAsString(), equalTo(""));
139+
}
140+
141+
@Test
142+
public void defaultContextPathCustomDeprecated() throws Exception {
143+
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
144+
.contextPath("/abc").createConnection(delegateConnection);
145+
146+
assertThat(getWebResponse("http://localhost/abc/def").getContentAsString(), equalTo("/abc"));
147+
}
148+
149+
@Test
150+
public void context() throws Exception {
151+
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
152+
.createConnection(webClient);
153+
93154
assertMvcProcessed("http://localhost/");
94155
assertDelegateProcessed("http://example.com/");
95156
}
@@ -104,7 +165,7 @@ public void mockMvc() throws Exception {
104165
public void mockMvcExampleDotCom() throws Exception {
105166
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
106167
.useMockMvcForHosts("example.com")
107-
.createConnection(delegateConnection);
168+
.createConnection(webClient);
108169

109170
assertMvcProcessed("http://localhost/");
110171
assertMvcProcessed("http://example.com/");
@@ -115,23 +176,23 @@ public void mockMvcExampleDotCom() throws Exception {
115176
public void mockMvcAlwaysUseMockMvc() throws Exception {
116177
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
117178
.alwaysUseMockMvc()
118-
.createConnection(delegateConnection);
179+
.createConnection(webClient);
119180

120181
assertMvcProcessed("http://other.com/");
121182
}
122183

123184
@Test
124185
public void defaultContextPathEmpty() throws Exception {
125186
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
126-
.createConnection(delegateConnection);
187+
.createConnection(webClient);
127188

128189
assertThat(getWebResponse("http://localhost/abc").getContentAsString(), equalTo(""));
129190
}
130191

131192
@Test
132193
public void defaultContextPathCustom() throws Exception {
133194
connection = new MockMvcWebConnectionBuilderSupport(wac) {}
134-
.contextPath("/abc").createConnection(delegateConnection);
195+
.contextPath("/abc").createConnection(webClient);
135196

136197
assertThat(getWebResponse("http://localhost/abc/def").getContentAsString(), equalTo("/abc"));
137198
}

spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebClientBuilderTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
3535
import org.springframework.tests.Assume;
3636
import org.springframework.tests.TestGroup;
37+
import org.springframework.web.bind.annotation.CookieValue;
3738
import org.springframework.web.bind.annotation.RequestMapping;
3839
import org.springframework.web.bind.annotation.RestController;
3940
import org.springframework.web.context.WebApplicationContext;
@@ -42,6 +43,7 @@
4243
import com.gargoylesoftware.htmlunit.WebClient;
4344
import com.gargoylesoftware.htmlunit.WebRequest;
4445
import com.gargoylesoftware.htmlunit.WebResponse;
46+
import com.gargoylesoftware.htmlunit.util.Cookie;
4547

4648
import static org.hamcrest.CoreMatchers.*;
4749
import static org.junit.Assert.*;
@@ -99,6 +101,17 @@ public void mockMvcSetupWithCustomWebClientDelegate() throws Exception {
99101
Assume.group(TestGroup.PERFORMANCE, () -> assertDelegateProcessed("http://example.com/"));
100102
}
101103

104+
// SPR-14066
105+
@Test
106+
public void cookieManagerShared() throws Exception {
107+
this.mockMvc = MockMvcBuilders.standaloneSetup(new CookieController()).build();
108+
this.webClient = mockMvcSetup(this.mockMvc).build();
109+
110+
assertThat(getWebResponse("http://localhost/").getContentAsString(), equalTo(""));
111+
this.webClient.getCookieManager().addCookie(new Cookie("localhost", "cookie", "cookieManagerShared"));
112+
assertThat(getWebResponse("http://localhost/").getContentAsString(), equalTo("cookieManagerShared"));
113+
}
114+
102115
private void assertMvcProcessed(String url) throws Exception {
103116
assertThat(getWebResponse(url).getContentAsString(), equalTo("mvc"));
104117
}
@@ -126,4 +139,11 @@ public String contextPath(HttpServletRequest request) {
126139
}
127140
}
128141

142+
@RestController
143+
static class CookieController {
144+
@RequestMapping("/")
145+
public String cookie(@CookieValue("cookie") String cookie) {
146+
return cookie;
147+
}
148+
}
129149
}

spring-test/src/test/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnectionTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* @author Rob Winch
3737
* @since 4.2
3838
*/
39+
@SuppressWarnings("deprecation")
3940
public class MockMvcWebConnectionTests {
4041

4142
private final WebClient webClient = new WebClient();
@@ -50,7 +51,7 @@ public void setup() {
5051

5152
@Test
5253
public void contextPathNull() throws IOException {
53-
this.webClient.setWebConnection(new MockMvcWebConnection(this.mockMvc, null));
54+
this.webClient.setWebConnection(new MockMvcWebConnection(this.mockMvc, (String) null));
5455

5556
Page page = this.webClient.getPage("http://localhost/context/a");
5657

0 commit comments

Comments
 (0)