Open
Description
While I am not sure this bug is directly linked to spring framework.
If you use the test framework with WebTestClient and restTemplate connecting to a mockServer. It creates a blocking process at the restTemplate level.
I first wanted to check if you guys were aware of this issue?
It seems to be linked to the mock server as well. As hitting an external server directly will work.
So WebClient(async) used in the test + RestTemplate in the app + MockServer --> return a concurrent issue.
So RestTemplate used in the test + RestTemplate in the app + MockServer --> works fine
So WebClient(async) used in the test + RestTemplate in the app + Direct server --> work fine
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
RestTemplate restTemplate;
TestController() {
restTemplate = new RestTemplateBuilder()
.build();
}
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<TestResponse> postTransaction(@Valid @RequestBody TestRequest testRequest,
@RequestHeader HttpHeaders headers) {
HttpEntity<testRequest> entity = new HttpEntity<>(testRequest, headers);
restTemplate.postForObject("http://localhost:6666/myTest", entity, TestResponse.class);
return null;
}
}
@ActiveProfiles("integration-test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@AutoConfigureWireMock(files = "file:./happy-path", port = 6666)
public class TestControllerIT {
@Autowired
private WebTestClient client;
@Test
public void testWithWebClient() throws Exception {
client.post().uri("/test")
.bodyValue(testRequest)
.header("Content-Type", "application/json")
.exchange()
.expectStatus().isEqualTo(200)
.expectBody();
}
}
Same test using RestTemplate will work fine.
@ActiveProfiles("integration-test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@AutoConfigureWireMock(files = "file:./happy-path", port = 6666)
public class TestControllerIT {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate testRestTemplate;
@Test
public void testWithRestTemplate() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> entity = testRestTemplate.exchange("http://localhost:" + port + "/test",
HttpMethod.POST,
new HttpEntity<>(testRequest, headers),
String.class);
assertEquals(HttpStatusCode.valueOf(200), entity.getStatusCode());
}
}
The error generated is :
10:24:54.004 [Test worker] WARN i.o.t.c.ExceptionAdviceHandler - Generic exception thrown: 500 Server Error: "{<EOL>"cause2":"java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"cause1":"java.io.IOException: java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"servlet":"com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet-3b84359c",<EOL>"cause0":"java.lang.RuntimeException: java.io.IOException: java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"message":"java.lang.RuntimeException: java.io.IOException: java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"url":"/test",<EOL>"status":"500"<EOL>}"
org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Server Error: "{<EOL>"cause2":"java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"cause1":"java.io.IOException: java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"servlet":"com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet-3b84359c",<EOL>"cause0":"java.lang.RuntimeException: java.io.IOException: java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"message":"java.lang.RuntimeException: java.io.IOException: java.util.concurrent.TimeoutException: Idle timeout expired: 30004/30000 ms",<EOL>"url":"/test",<EOL>"status":"500"<EOL>}"
at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:102)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:186)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:137)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:942)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:891)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:790)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:507)
at xxxTestController.postTransaction(TestController.java:64)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:547)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:113)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201)
at org.springframework.test.web.servlet.client.MockMvcHttpConnector.connect(MockMvcHttpConnector.java:106)
at org.springframework.test.web.reactive.server.WiretapConnector.connect(WiretapConnector.java:71)
at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.exchange(ExchangeFunctions.java:102)
at org.springframework.test.web.reactive.server.DefaultWebTestClient$DefaultRequestBodyUriSpec.exchange(DefaultWebTestClient.java:359)
Activity