Add support for Jetty Reactive Streams HTTP client
Leverage https://github.com/jetty-project/jetty-reactive-httpclient to add support for Jetty in WebClient via JettyClientHttpConnector. Implemented with buffer copy instead of optimized buffer wrapping because the latter hangs since Callback#succeeded doesn't allow releasing the buffer and requesting more data at different times (required for Mono<DataBuffer> for example). See https://github.com/eclipse/jetty.project/issues/2429. Issue: SPR-15092
This commit is contained in:
committed by
Sebastien Deleuze
parent
3c9049d530
commit
a87764f1fd
@@ -32,6 +32,8 @@ import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -46,6 +48,9 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.http.client.reactive.JettyClientHttpConnector;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.http.codec.Pojo;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@@ -56,18 +61,35 @@ import static org.junit.Assert.*;
|
||||
* @author Brian Clozel
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Denys Ivano
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class WebClientIntegrationTests {
|
||||
|
||||
private MockWebServer server;
|
||||
|
||||
private WebClient webClient;
|
||||
|
||||
@Parameterized.Parameter(0)
|
||||
public ClientHttpConnector connector;
|
||||
|
||||
@Parameterized.Parameters(name = "webClient [{0}]")
|
||||
public static Object[][] arguments() {
|
||||
|
||||
return new Object[][] {
|
||||
{new JettyClientHttpConnector()},
|
||||
{new ReactorClientHttpConnector()}
|
||||
};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.server = new MockWebServer();
|
||||
this.webClient = WebClient.create(this.server.url("/").toString());
|
||||
this.webClient = WebClient
|
||||
.builder()
|
||||
.clientConnector(this.connector)
|
||||
.baseUrl(this.server.url("/").toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -124,6 +146,28 @@ public class WebClientIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReceivePlainTextFlux() throws Exception {
|
||||
prepareResponse(response -> response.setBody("Hello Spring!"));
|
||||
|
||||
Flux<String> result = this.webClient.get()
|
||||
.uri("/greeting?name=Spring")
|
||||
.header("X-Test-Header", "testvalue")
|
||||
.exchange()
|
||||
.flatMapMany(response -> response.bodyToFlux(String.class));
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNext("Hello Spring!")
|
||||
.expectComplete().verify(Duration.ofSeconds(3));
|
||||
|
||||
expectRequestCount(1);
|
||||
expectRequest(request -> {
|
||||
assertEquals("testvalue", request.getHeader("X-Test-Header"));
|
||||
assertEquals("*/*", request.getHeader(HttpHeaders.ACCEPT));
|
||||
assertEquals("/greeting?name=Spring", request.getPath());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReceiveJsonAsString() {
|
||||
String content = "{\"bar\":\"barbar\",\"foo\":\"foofoo\"}";
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.Parameterized;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.MonoProcessor;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -30,11 +32,16 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.http.client.reactive.JettyClientHttpConnector;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.http.codec.ServerSentEvent;
|
||||
import org.springframework.http.server.reactive.AbstractHttpHandlerIntegrationTests;
|
||||
import org.springframework.http.server.reactive.HttpHandler;
|
||||
import org.springframework.http.server.reactive.bootstrap.JettyHttpServer;
|
||||
import org.springframework.http.server.reactive.bootstrap.ReactorHttpServer;
|
||||
import org.springframework.http.server.reactive.bootstrap.TomcatHttpServer;
|
||||
import org.springframework.http.server.reactive.bootstrap.UndertowHttpServer;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -56,12 +63,33 @@ public class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests {
|
||||
|
||||
private WebClient webClient;
|
||||
|
||||
@Parameterized.Parameter(1)
|
||||
public ClientHttpConnector connector;
|
||||
|
||||
@Parameterized.Parameters(name = "server [{0}] webClient [{1}]")
|
||||
public static Object[][] arguments() {
|
||||
File base = new File(System.getProperty("java.io.tmpdir"));
|
||||
return new Object[][] {
|
||||
{new JettyHttpServer(), new ReactorClientHttpConnector()},
|
||||
{new JettyHttpServer(), new JettyClientHttpConnector()},
|
||||
{new ReactorHttpServer(), new ReactorClientHttpConnector()},
|
||||
{new ReactorHttpServer(), new JettyClientHttpConnector()},
|
||||
{new TomcatHttpServer(base.getAbsolutePath()), new ReactorClientHttpConnector()},
|
||||
{new TomcatHttpServer(base.getAbsolutePath()), new JettyClientHttpConnector()},
|
||||
{new UndertowHttpServer(), new ReactorClientHttpConnector()},
|
||||
{new UndertowHttpServer(), new JettyClientHttpConnector()}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
super.setup();
|
||||
this.webClient = WebClient.create("http://localhost:" + this.port + "/sse");
|
||||
this.webClient = WebClient
|
||||
.builder()
|
||||
.clientConnector(this.connector)
|
||||
.baseUrl("http://localhost:" + this.port + "/sse")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user