Skip to content

Commit 6634d00

Browse files
authored
DefaultReactiveElasticsearchClient handle 5xx error with empty body
Original Pull Request #1713 Closes #1712
1 parent f08c34e commit 6634d00

File tree

2 files changed

+53
-17
lines changed

2 files changed

+53
-17
lines changed

Diff for: src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java

+4
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,10 @@ private <T> Publisher<? extends T> handleServerError(Request request, ClientResp
866866
String mediaType = response.headers().contentType().map(MediaType::toString).orElse(XContentType.JSON.mediaType());
867867

868868
return response.body(BodyExtractors.toMono(byte[].class)) //
869+
.switchIfEmpty(Mono
870+
.error(new ElasticsearchStatusException(String.format("%s request to %s returned error code %s and no body.",
871+
request.getMethod(), request.getEndpoint(), statusCode), status))
872+
)
869873
.map(bytes -> new String(bytes, StandardCharsets.UTF_8)) //
870874
.flatMap(content -> contentOrError(content, mediaType, status))
871875
.flatMap(unused -> Mono

Diff for: src/test/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClientTest.java

+49-17
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,29 @@
2222
import reactor.core.publisher.Mono;
2323
import reactor.test.StepVerifier;
2424

25+
import java.net.URI;
26+
import java.util.Optional;
2527
import java.util.function.Function;
2628

29+
import org.elasticsearch.ElasticsearchStatusException;
30+
import org.elasticsearch.action.get.GetRequest;
2731
import org.elasticsearch.action.search.SearchRequest;
2832
import org.elasticsearch.client.Request;
2933
import org.elasticsearch.index.query.QueryBuilders;
3034
import org.elasticsearch.search.builder.SearchSourceBuilder;
3135
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
32-
import org.junit.jupiter.api.BeforeEach;
36+
import org.junit.jupiter.api.DisplayName;
3337
import org.junit.jupiter.api.Test;
3438
import org.junit.jupiter.api.extension.ExtendWith;
3539
import org.mockito.ArgumentCaptor;
3640
import org.mockito.Mock;
41+
import org.mockito.Spy;
3742
import org.mockito.junit.jupiter.MockitoExtension;
43+
import org.springframework.http.HttpStatus;
44+
import org.springframework.web.reactive.function.client.ClientResponse;
45+
import org.springframework.web.reactive.function.client.WebClient;
3846
import org.springframework.web.reactive.function.client.WebClient.ResponseSpec;
47+
import org.springframework.web.util.UriBuilder;
3948

4049
/**
4150
* @author Peter-Josef Meisch
@@ -46,30 +55,24 @@ class DefaultReactiveElasticsearchClientTest {
4655
@Mock private HostProvider hostProvider;
4756

4857
@Mock private Function<SearchRequest, Request> searchRequestConverter;
58+
@Spy private RequestCreator requestCreator;
4959

50-
private DefaultReactiveElasticsearchClient client;
51-
52-
@BeforeEach
53-
void setUp() {
54-
client = new DefaultReactiveElasticsearchClient(hostProvider, new RequestCreator() {
55-
@Override
56-
public Function<SearchRequest, Request> search() {
57-
return searchRequestConverter;
58-
}
59-
}) {
60-
@Override
61-
public Mono<ResponseSpec> execute(ReactiveElasticsearchClientCallback callback) {
62-
return Mono.empty();
63-
}
64-
};
65-
}
60+
@Mock private WebClient webClient;
6661

6762
@Test
6863
void shouldSetAppropriateRequestParametersOnCount() {
6964

65+
when(requestCreator.search()).thenReturn(searchRequestConverter);
7066
SearchRequest searchRequest = new SearchRequest("someindex") //
7167
.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
7268

69+
ReactiveElasticsearchClient client = new DefaultReactiveElasticsearchClient(hostProvider, requestCreator) {
70+
@Override
71+
public Mono<ResponseSpec> execute(ReactiveElasticsearchClientCallback callback) {
72+
return Mono.empty();
73+
}
74+
};
75+
7376
client.count(searchRequest).as(StepVerifier::create).verifyComplete();
7477

7578
ArgumentCaptor<SearchRequest> captor = ArgumentCaptor.forClass(SearchRequest.class);
@@ -79,4 +82,33 @@ void shouldSetAppropriateRequestParametersOnCount() {
7982
assertThat(source.trackTotalHitsUpTo()).isEqualTo(TRACK_TOTAL_HITS_ACCURATE);
8083
assertThat(source.fetchSource()).isEqualTo(FetchSourceContext.DO_NOT_FETCH_SOURCE);
8184
}
85+
86+
@Test // #1712
87+
@DisplayName("should throw ElasticsearchStatusException on server 5xx with empty body")
88+
void shouldThrowElasticsearchStatusExceptionOnServer5xxWithEmptyBody() {
89+
90+
when(hostProvider.getActive(any())).thenReturn(Mono.just(webClient));
91+
WebClient.RequestBodyUriSpec requestBodyUriSpec = mock(WebClient.RequestBodyUriSpec.class);
92+
when(requestBodyUriSpec.uri((Function<UriBuilder, URI>) any())).thenReturn(requestBodyUriSpec);
93+
when(requestBodyUriSpec.attribute(any(), any())).thenReturn(requestBodyUriSpec);
94+
when(requestBodyUriSpec.headers(any())).thenReturn(requestBodyUriSpec);
95+
when(webClient.method(any())).thenReturn(requestBodyUriSpec);
96+
when(requestBodyUriSpec.exchangeToMono(any())).thenAnswer(invocationOnMock -> {
97+
Function<ClientResponse, ? extends Mono<?>> responseHandler = invocationOnMock.getArgument(0);
98+
ClientResponse clientResponse = mock(ClientResponse.class);
99+
when(clientResponse.statusCode()).thenReturn(HttpStatus.SERVICE_UNAVAILABLE);
100+
ClientResponse.Headers headers = mock(ClientResponse.Headers.class);
101+
when(headers.contentType()).thenReturn(Optional.empty());
102+
when(clientResponse.headers()).thenReturn(headers);
103+
when(clientResponse.body(any())).thenReturn(Mono.empty());
104+
return responseHandler.apply(clientResponse);
105+
});
106+
107+
ReactiveElasticsearchClient client = new DefaultReactiveElasticsearchClient(hostProvider, requestCreator);
108+
109+
client.get(new GetRequest("42")) //
110+
.as(StepVerifier::create) //
111+
.expectError(ElasticsearchStatusException.class) //
112+
.verify(); //
113+
}
82114
}

0 commit comments

Comments
 (0)