Skip to content

Commit d3c92b8

Browse files
committed
Deprecate MockMvcClientHttpRequestFactory and copy into servlet.client
Fixes gh-31275 Signed-off-by: Rob Worsnop <[email protected]>
1 parent 41afed8 commit d3c92b8

File tree

6 files changed

+240
-2
lines changed

6 files changed

+240
-2
lines changed

spring-test/src/main/java/org/springframework/test/web/client/MockMvcClientHttpRequestFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.mock.http.client.MockClientHttpResponse;
3535
import org.springframework.mock.web.MockHttpServletResponse;
3636
import org.springframework.test.web.servlet.MockMvc;
37+
import org.springframework.test.web.servlet.client.RestTestClient;
3738
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
3839
import org.springframework.util.Assert;
3940
import org.springframework.util.StringUtils;
@@ -45,7 +46,9 @@
4546
*
4647
* @author Rossen Stoyanchev
4748
* @since 3.2
49+
* @deprecated in favor of {@link RestTestClient#bindTo(MockMvc)}
4850
*/
51+
@Deprecated(since = "7.0")
4952
public class MockMvcClientHttpRequestFactory implements ClientHttpRequestFactory {
5053

5154
private final MockMvc mockMvc;

spring-test/src/main/java/org/springframework/test/web/servlet/client/AbstractMockServerSpec.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import jakarta.servlet.Filter;
2020

2121
import org.springframework.http.client.ClientHttpRequestFactory;
22-
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
2322
import org.springframework.test.web.servlet.DispatcherServletCustomizer;
2423
import org.springframework.test.web.servlet.MockMvc;
2524
import org.springframework.test.web.servlet.RequestBuilder;
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright 2002-present the original author or authors.
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+
* https://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+
17+
package org.springframework.test.web.servlet.client;
18+
19+
import java.net.URI;
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.List;
22+
23+
import jakarta.servlet.http.Cookie;
24+
import org.jspecify.annotations.Nullable;
25+
26+
import org.springframework.http.HttpHeaders;
27+
import org.springframework.http.HttpMethod;
28+
import org.springframework.http.HttpStatus;
29+
import org.springframework.http.HttpStatusCode;
30+
import org.springframework.http.client.ClientHttpRequest;
31+
import org.springframework.http.client.ClientHttpRequestFactory;
32+
import org.springframework.http.client.ClientHttpResponse;
33+
import org.springframework.mock.http.client.MockClientHttpRequest;
34+
import org.springframework.mock.http.client.MockClientHttpResponse;
35+
import org.springframework.mock.web.MockHttpServletResponse;
36+
import org.springframework.test.web.servlet.MockMvc;
37+
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
38+
import org.springframework.util.Assert;
39+
import org.springframework.util.StringUtils;
40+
41+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
42+
43+
/**
44+
* A {@link ClientHttpRequestFactory} for requests executed via {@link MockMvc}.
45+
*
46+
* @author Rossen Stoyanchev
47+
* @author Rob Worsnop
48+
* @since 7.0
49+
*/
50+
class MockMvcClientHttpRequestFactory implements ClientHttpRequestFactory {
51+
52+
private final MockMvc mockMvc;
53+
54+
55+
MockMvcClientHttpRequestFactory(MockMvc mockMvc) {
56+
Assert.notNull(mockMvc, "MockMvc must not be null");
57+
this.mockMvc = mockMvc;
58+
}
59+
60+
61+
@Override
62+
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
63+
return new MockClientHttpRequest(httpMethod, uri) {
64+
@Override
65+
public ClientHttpResponse executeInternal() {
66+
return getClientHttpResponse(httpMethod, uri, getHeaders(), getBodyAsBytes());
67+
}
68+
};
69+
}
70+
71+
private ClientHttpResponse getClientHttpResponse(
72+
HttpMethod httpMethod, URI uri, HttpHeaders requestHeaders, byte[] requestBody) {
73+
74+
try {
75+
Cookie[] cookies = parseCookies(requestHeaders.get(HttpHeaders.COOKIE));
76+
MockHttpServletRequestBuilder requestBuilder = request(httpMethod, uri)
77+
.content(requestBody).headers(requestHeaders);
78+
if (cookies.length > 0) {
79+
requestBuilder.cookie(cookies);
80+
}
81+
MockHttpServletResponse servletResponse = this.mockMvc
82+
.perform(requestBuilder)
83+
.andReturn()
84+
.getResponse();
85+
86+
HttpStatusCode status = HttpStatusCode.valueOf(servletResponse.getStatus());
87+
byte[] body = servletResponse.getContentAsByteArray();
88+
if (body.length == 0) {
89+
String error = servletResponse.getErrorMessage();
90+
if (StringUtils.hasLength(error)) {
91+
// sendError message as default body
92+
body = error.getBytes(StandardCharsets.UTF_8);
93+
}
94+
}
95+
96+
MockClientHttpResponse clientResponse = new MockClientHttpResponse(body, status);
97+
clientResponse.getHeaders().putAll(getResponseHeaders(servletResponse));
98+
return clientResponse;
99+
}
100+
catch (Exception ex) {
101+
byte[] body = ex.toString().getBytes(StandardCharsets.UTF_8);
102+
return new MockClientHttpResponse(body, HttpStatus.INTERNAL_SERVER_ERROR);
103+
}
104+
}
105+
106+
private static Cookie[] parseCookies(@Nullable List<String> headerValues) {
107+
if (headerValues == null) {
108+
return new Cookie[0];
109+
}
110+
return headerValues.stream()
111+
.flatMap(header -> StringUtils.commaDelimitedListToSet(header).stream())
112+
.map(MockMvcClientHttpRequestFactory::parseCookie)
113+
.toArray(Cookie[]::new);
114+
}
115+
116+
private static Cookie parseCookie(String cookie) {
117+
String[] parts = StringUtils.split(cookie, "=");
118+
Assert.isTrue(parts != null && parts.length == 2, "Invalid cookie: '" + cookie + "'");
119+
return new Cookie(parts[0], parts[1]);
120+
}
121+
122+
private HttpHeaders getResponseHeaders(MockHttpServletResponse response) {
123+
HttpHeaders headers = new HttpHeaders();
124+
for (String name : response.getHeaderNames()) {
125+
List<String> values = response.getHeaders(name);
126+
for (String value : values) {
127+
headers.add(name, value);
128+
}
129+
}
130+
return headers;
131+
}
132+
133+
}

spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import org.springframework.test.json.JsonComparator;
3939
import org.springframework.test.json.JsonCompareMode;
4040
import org.springframework.test.json.JsonComparison;
41-
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
4241
import org.springframework.test.web.servlet.DispatcherServletCustomizer;
4342
import org.springframework.test.web.servlet.MockMvc;
4443
import org.springframework.test.web.servlet.RequestBuilder;

spring-test/src/test/java/org/springframework/test/web/client/samples/MockMvcClientHttpRequestFactoryTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
@ExtendWith(SpringExtension.class)
5656
@WebAppConfiguration
5757
@ContextConfiguration
58+
@SuppressWarnings("deprecation")
5859
public class MockMvcClientHttpRequestFactoryTests {
5960

6061
@Autowired
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2002-present the original author or authors.
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+
* https://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+
17+
package org.springframework.test.web.servlet.client;
18+
19+
import java.io.IOException;
20+
21+
import jakarta.servlet.http.Cookie;
22+
import jakarta.servlet.http.HttpServletResponse;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.extension.ExtendWith;
26+
27+
import org.springframework.test.context.junit.jupiter.SpringExtension;
28+
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
29+
import org.springframework.test.web.servlet.MockMvc;
30+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
31+
import org.springframework.web.bind.annotation.CookieValue;
32+
import org.springframework.web.bind.annotation.GetMapping;
33+
import org.springframework.web.bind.annotation.RestController;
34+
35+
/**
36+
* Tests that use a {@link RestTestClient} configured with a
37+
* {@link MockMvcClientHttpRequestFactory} that is in turn configured with a
38+
* {@link MockMvc} instance that uses a standalone controller
39+
*
40+
* @author Rob Worsnop
41+
*/
42+
@ExtendWith(SpringExtension.class)
43+
public class MockMvcClientHttpRequestFactoryTests {
44+
45+
private RestTestClient client;
46+
47+
@BeforeEach
48+
public void setup() {
49+
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
50+
this.client = RestTestClient.bindTo(mockMvc).build();
51+
}
52+
53+
@Test
54+
public void withResult() {
55+
client.get()
56+
.uri("/foo")
57+
.cookie("session", "12345")
58+
.exchange()
59+
.expectCookie().valueEquals("session", "12345")
60+
.expectBody(String.class)
61+
.isEqualTo("bar");
62+
}
63+
64+
@Test
65+
public void withError() {
66+
client.get()
67+
.uri("/error")
68+
.exchange()
69+
.expectStatus().isBadRequest()
70+
.expectBody().isEmpty();
71+
}
72+
73+
@Test
74+
public void withErrorAndBody() {
75+
client.get().uri("/errorbody")
76+
.exchange()
77+
.expectStatus().isBadRequest()
78+
.expectBody(String.class)
79+
.isEqualTo("some really bad request");
80+
}
81+
82+
@RestController
83+
static class TestController {
84+
85+
@GetMapping(value = "/foo")
86+
public void foo(@CookieValue("session") String session, HttpServletResponse response) throws IOException {
87+
response.getWriter().write("bar");
88+
response.addCookie(new Cookie("session", session));
89+
}
90+
91+
@GetMapping(value = "/error")
92+
public void handleError(HttpServletResponse response) throws Exception {
93+
response.sendError(400);
94+
}
95+
96+
@GetMapping(value = "/errorbody")
97+
public void handleErrorWithBody(HttpServletResponse response) throws Exception {
98+
response.sendError(400);
99+
response.getWriter().write("some really bad request");
100+
}
101+
}
102+
103+
}

0 commit comments

Comments
 (0)