Fix WebClientIntegrationTest#applyAttributesToNativeRequest flaky test

For Reactor Netty and Reactor Netty 2 (with Netty 5), the attributes are
stored as an `Attribute` on the netty channel. Reactor Netty replaces
the channel with a static placeholder one once the request has been
processed and as such, capturing the native request in the test will
lead to asserting an attribute-less channel.

This change switches to capturing the `Attribute` itself, which is a
value-holder that can be asserted later on.

Closes gh-33909
This commit is contained in:
Simon Baslé 2024-11-18 16:30:16 +01:00
parent f5c3f3522e
commit d597d2e159
1 changed files with 18 additions and 8 deletions

View File

@ -83,7 +83,6 @@ import org.springframework.web.reactive.function.client.WebClient.ResponseSpec;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static org.junit.jupiter.params.provider.Arguments.argumentSet;
/**
@ -108,6 +107,7 @@ class WebClientIntegrationTests {
static Stream<Arguments> arguments() {
return Stream.of(
argumentSet("Reactor Netty", new ReactorClientHttpConnector()),
argumentSet("Reactor Netty 2", new ReactorNetty2ClientHttpConnector()),
argumentSet("JDK", new JdkClientHttpConnector()),
argumentSet("Jetty", new JettyClientHttpConnector()),
argumentSet("HttpComponents", new HttpComponentsClientHttpConnector())
@ -193,8 +193,6 @@ class WebClientIntegrationTests {
@ParameterizedWebClientTest
void applyAttributesToNativeRequest(ClientHttpConnector connector) {
assumeFalse(connector instanceof ReactorClientHttpConnector,
"Temporarily disabling flaky test for Reactor Netty");
startServer(connector);
prepareResponse(response -> {});
@ -202,20 +200,32 @@ class WebClientIntegrationTests {
Mono<Void> result = this.webClient.get()
.uri("/pojo")
.attribute("foo","bar")
.httpRequest(clientHttpRequest -> nativeRequest.set(clientHttpRequest.getNativeRequest()))
.httpRequest(clientHttpRequest -> {
if (clientHttpRequest instanceof ChannelOperations<?,?> nettyReq) {
nativeRequest.set(nettyReq.channel().attr(ReactorClientHttpConnector.ATTRIBUTES_KEY));
}
else if (clientHttpRequest instanceof reactor.netty5.channel.ChannelOperations<?,?> nettyReq) {
nativeRequest.set(nettyReq.channel().attr(ReactorNetty2ClientHttpConnector.ATTRIBUTES_KEY));
}
else {
nativeRequest.set(clientHttpRequest.getNativeRequest());
}
})
.retrieve()
.bodyToMono(Void.class);
StepVerifier.create(result).expectComplete().verify();
if (nativeRequest.get() instanceof ChannelOperations<?,?> nativeReq) {
Attribute<Map<String, Object>> attributes = nativeReq.channel().attr(ReactorClientHttpConnector.ATTRIBUTES_KEY);
if (nativeRequest.get() instanceof Attribute<?>) {
@SuppressWarnings("unchecked")
Attribute<Map<String, Object>> attributes = (Attribute<Map<String, Object>>) nativeRequest.get();
assertThat(attributes.get()).isNotNull();
assertThat(attributes.get()).containsEntry("foo", "bar");
}
else if (nativeRequest.get() instanceof reactor.netty5.channel.ChannelOperations<?,?> nativeReq) {
else if (nativeRequest.get() instanceof io.netty5.util.Attribute<?>) {
@SuppressWarnings("unchecked")
io.netty5.util.Attribute<Map<String, Object>> attributes =
nativeReq.channel().attr(ReactorNetty2ClientHttpConnector.ATTRIBUTES_KEY);
(io.netty5.util.Attribute<Map<String, Object>>) nativeRequest.get();
assertThat(attributes.get()).isNotNull();
assertThat(attributes.get()).containsEntry("foo", "bar");
}