- Notifications
You must be signed in to change notification settings - Fork 38.8k
Description
WebTestClient
has a special case when a Void
response is expected. Method WebTestClient.ResponseSpec#returnResult(java.lang.Class<T>)
has this documentation comment:
Note that when {@code Void.class} is passed in, the response body is consumed and released.
The same special case logic is not applied to the overloaded version of this method: WebTestClient.ResponseSpec#returnResult(ParameterizedTypeReference<T>)
. This is a bit unexpected; and caused a memory leak in my tests when I swapped a Class parameter for a ParameterizedTypeReference parameter. The following sample code shows the problem (additional GC is forced to make the leak happen faster; netty's leak detection happens on GC):
import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.netty.http.client.HttpClient; class Scratch { public static void main(String[] args) throws Exception { var client = WebTestClient.bindToServer(new ReactorClientHttpConnector(HttpClient.create())) .build(); var b = client.get().uri("http://localhost:8000"); long count = 0; while(true) { count += 1; if (count % 10000 == 0) { System.out.printf("Done %d requests forcing a G\n", count); System.gc(); } b.exchange() .expectStatus().isEqualTo(200) //.returnResult(Void.class); // <-- doesn't leak .returnResult(ParameterizedTypeReference.forType(Void.class)); // <-- leaks } } }
The workaround is to use the Class
signature, or consume the response body some other way using e.g. by specifying .consumeWith(...)
.